def paintEvent(self, e): painter = QPainter(self) # Draw empty button (no label or icon). buttonStyle = QStyleOptionButton() self.initStyleOption(buttonStyle) buttonStyle.text = '' buttonStyle.icon = QIcon() buttonStyle.iconSize = QSize(-1, -1) self.style().drawControl(QStyle.CE_PushButton, buttonStyle, painter, self) # Get button label style. labelStyle = QStyleOptionButton() self.initStyleOption(labelStyle) labelStyle.rect = self.style().subElementRect(QStyle.SE_PushButtonContents, labelStyle, self) # Clip everything we paint to label area. painter.setClipRect(labelStyle.rect) painter.setClipping(True) # TODO painter.translate(-200, 0); # Has to happen after we set clipping. # Draw label (optionally with icon), similar to how Qt does it (src/widgets/styles/qcommonstyle.cpp in Qt 5.3). self.style().drawControl(QStyle.CE_PushButtonLabel, labelStyle, painter, self)
def draw(self, painter: QPainter): assert self.crop, 'crop must be set' # Compute painter regions for the crop and the blur all_region = QRegion(painter.viewport()) crop_region = QRegion(self.crop) blur_region = all_region.subtracted(crop_region) # Let the QGraphicsBlurEffect only paint in blur_region painter.setClipRegion(blur_region) # Fill with black and set opacity so that the blurred region is drawn darker if self.BLUR_DARKEN > 0.0: painter.fillRect(painter.viewport(), Qt.black) painter.setOpacity(1 - self.BLUR_DARKEN) # Draw the blur effect super().draw(painter) # Restore clipping and opacity painter.setClipping(False) painter.setOpacity(1.0) # Get the source pixmap pixmap, offset = self.sourcePixmap(Qt.DeviceCoordinates, QGraphicsEffect.NoPad) painter.setWorldTransform(QTransform()) # Get the source by adding the offset to the crop location source = self.crop if self.CROP_OFFSET_ENABLED: source = source.translated(self.CROP_OFFSET) painter.drawPixmap(self.crop.topLeft() + offset, pixmap, source)
def paintEvent(self, e): painter = QPainter(self) painter.setClipping(True) painter.rotate(-90) painter.translate(-self.height(), 0) flags = Qt.AlignCenter self.text_rect = painter.boundingRect(0, 0, self.height(), self.width(), flags, self.text) painter.drawText(self.text_rect, flags, self.text) painter.end()
def paintEvent(self, event): painter = QPainter(self) # erase background painter.setBackground(QBrush(Layer.color(LayerType.background))) painter.setClipping(True) painter.eraseRect(self.rect()) # draw document if self._ctrl is not None: # draw grid painter.setRenderHint(QPainter.Antialiasing, False) pen = QPen(Layer.color(LayerType.grid)) pen.setCapStyle(Qt.RoundCap) pen.setJoinStyle(Qt.RoundJoin) pen.setWidth(0) painter.setTransform(self._transform) painter.setPen(pen) self._drawGrid(painter) # draw drawables # painter.setRenderHint(QPainter.Antialiasing) for d in self._ctrl.getDrawables(): d.draw(painter) painter.end()
def paintEvent(self, event): p = QPainter() p.begin(self) self._normalMap.render(p, event.rect()) p.setPen(Qt.black) p.drawText(self.rect(), Qt.AlignBottom | Qt.TextWordWrap, "Map data CCBYSA 2009 OpenStreetMap.org contributors") p.end() if self.zoomed: dim = min(self.width(), self.height()) magnifierSize = min(MAX_MAGNIFIER, dim * 2 / 3) radius = magnifierSize / 2 ring = radius - 15 box = QSize(magnifierSize, magnifierSize) # reupdate our mask if self.maskPixmap.size() != box: self.maskPixmap = QPixmap(box) self.maskPixmap.fill(Qt.transparent) g = QRadialGradient() g.setCenter(radius, radius) g.setFocalPoint(radius, radius) g.setRadius(radius) g.setColorAt(1.0, QColor(255, 255, 255, 0)) g.setColorAt(0.5, QColor(128, 128, 128, 255)) mask = QPainter(self.maskPixmap) mask.setRenderHint(QPainter.Antialiasing) mask.setCompositionMode(QPainter.CompositionMode_Source) mask.setBrush(g) mask.setPen(Qt.NoPen) mask.drawRect(self.maskPixmap.rect()) mask.setBrush(QColor(Qt.transparent)) mask.drawEllipse(g.center(), ring, ring) mask.end() center = self.dragPos - QPoint(0, radius) center += QPoint(0, radius / 2) corner = center - QPoint(radius, radius) xy = center * 2 - QPoint(radius, radius) # only set the dimension to the magnified portion if self.zoomPixmap.size() != box: self.zoomPixmap = QPixmap(box) self.zoomPixmap.fill(Qt.lightGray) if True: p = QPainter(self.zoomPixmap) p.translate(-xy) self._largeMap.render(p, QRect(xy, box)) p.end() clipPath = QPainterPath() clipPath.addEllipse(QPointF(center), ring, ring) p = QPainter(self) p.setRenderHint(QPainter.Antialiasing) p.setClipPath(clipPath) p.drawPixmap(corner, self.zoomPixmap) p.setClipping(False) p.drawPixmap(corner, self.maskPixmap) p.setPen(Qt.gray) p.drawPath(clipPath) if self.invert: p = QPainter(self) p.setCompositionMode(QPainter.CompositionMode_Difference) p.fillRect(event.rect(), Qt.white) p.end()
def drawWaveforms(self): painter = QPainter(self.pixmap) length = Rhd2000DataBlock.getSamplesPerDataBlock( ) * self.numUsbBlocksToPlot polyline = [0] * (length + 1) # Assume all frames are the same size. yAxisLength = (self.frameList[self.numFramesIndex[self.selectedPort]] [0].height() - 2) / 2.0 tAxisLength = self.frameList[self.numFramesIndex[ self.selectedPort]][0].width() - 1 for j in range( len(self.frameList[self.numFramesIndex[self.selectedPort]])): stream = self.selectedChannelIndex( j + self.topLeftFrame[self.selectedPort]).boardStream channel = self.selectedChannelIndex( j + self.topLeftFrame[self.selectedPort]).chipChannel stype = self.selectedChannelIndex( j + self.topLeftFrame[self.selectedPort]).signalType if self.selectedChannelIndex( j + self.topLeftFrame[self.selectedPort]).enabled: xOffset = self.frameList[self.numFramesIndex[ self.selectedPort]][j].left() + 1 xOffset += self.tPosition * tAxisLength / self.tScale # Set clipping region adjustedFrame = copy( self.frameList[self.numFramesIndex[self.selectedPort]][j]) adjustedFrame.adjust(0, 1, 0, 0) painter.setClipRect(adjustedFrame) # Erase segment of old wavefrom eraseBlock = copy(adjustedFrame) eraseBlock.setLeft(xOffset) eraseBlock.setRight( (tAxisLength * (1000.0 / self.sampleRate) / self.tScale) * (length - 1) + xOffset) painter.eraseRect(eraseBlock) # Redraw y = 0 axis self.drawAxisLines(painter, j) if stype == constants.AmplifierSignal: # Plot RHD2000 amplifier waveform tStepMsec = 1000.0 / self.sampleRate xScaleFactor = tAxisLength * tStepMsec / self.tScale yScaleFactor = -yAxisLength / self.yScale yOffset = self.frameList[self.numFramesIndex[ self.selectedPort]][j].center().y() # build waveform for i in range(length): polyline[i + 1] = QPointF( xScaleFactor * i + xOffset, yScaleFactor * self.signalProcessor. amplifierPostFilter[stream][channel][i] + yOffset) # join to old waveform if self.tPosition == 0.0: polyline[0] = polyline[1] else: polyline[0] = QPointF( xScaleFactor * -1 + xOffset, yScaleFactor * self.plotDataOld[ j + self.topLeftFrame[self.selectedPort]] + yOffset) # save last point in waveform to join to next segment self.plotDataOld[j + self.topLeftFrame[ self. selectedPort]] = self.signalProcessor.amplifierPostFilter[ stream][channel][length - 1] # draw waveform painter.setPen(Qt.blue) if self.pointPlotMode: painter.drawPoints(QPolygonF(polyline)) else: painter.drawPolyline(QPolygonF(polyline)) elif stype == constants.AuxInputSignal: # Plot RHD2000 auxiliary input signal tStepMsec = 1000.0 / (self.sampleRate / 4) xScaleFactor = tAxisLength * tStepMsec / self.tScale yScaleFactor = -(2.0 * yAxisLength) / 2.5 yOffset = self.frameList[self.numFramesIndex[ self.selectedPort]][j].bottom() # build waveform for i in range(length / 4): polyline[i + 1] = QPointF( xScaleFactor * i + xOffset, yScaleFactor * self.signalProcessor.auxChannel[stream][channel][i] + yOffset) # join to old waveform if self.tPosition == 0.0: polyline[0] = polyline[1] else: polyline[0] = QPointF( xScaleFactor * -1 + xOffset, yScaleFactor * self.plotDataOld[ j + self.topLeftFrame[self.selectedPort]] + yOffset) # save last point in waveform to join to next segment self.plotDataOld[j + self.topLeftFrame[ self.selectedPort]] = self.signalProcessor.auxChannel[ stream][channel][(length / 4) - 1] # draw waveform pen = QPen() pen.setColor(QColor(200, 50, 50)) painter.setPen(pen) polyline = polyline[:(length // 4) + 1] if self.pointPlotMode: painter.drawPoints(QPolygonF(polyline)) else: painter.drawPolyline(QPolygonF(polyline)) elif stype == constants.SupplyVoltageSignal: # Plot RHD2000 supply voltage signal tStepMsec = 1000.0 / (self.sampleRate / 60.0) xScaleFactor = tAxisLength * tStepMsec / self.tScale yScaleFactor = -(2.0 * yAxisLength) / 1.5 yOffset = self.frameList[self.numFramesIndex[ self.selectedPort]][j].bottom() voltageLow = False voltageOutOfRange = False # build waveform for i in range(length / 60): voltage = self.signalProcessor.supplyVoltage[stream][i] polyline[i + 1] = QPointF( xScaleFactor * i + xOffset, yScaleFactor * (voltage - 2.5) + yOffset) if voltage < 2.9 or voltage > 3.6: voltageOutOfRange = True elif voltage < 3.2: voltageLow = True # join to old waveform if self.tPosition == 0.0: polyline[0] = polyline[1] else: polyline[0] = QPointF( xScaleFactor * -1 + xOffset, yScaleFactor * (self.plotDataOld[j + self.topLeftFrame[ self.selectedPort]] - 2.5) + yOffset) # save last point in waveform to join to next segment self.plotDataOld[j + self.topLeftFrame[ self. selectedPort]] = self.signalProcessor.supplyVoltage[ stream][(length / 60) - 1] # draw waveform painter.setPen(Qt.green) if voltageLow: painter.setPen(Qt.yellow) if voltageOutOfRange: painter.setPen(Qt.red) polyline = polyline[:(length // 60) + 1] if self.pointPlotMode: painter.drawPoints(QPolygonF(polyline)) else: painter.drawPolyline(QPolygonF(polyline)) elif stype == constants.BoardAdcSignal: # Plot USB interface board ADC input signal tStepMsec = 1000.0 / self.sampleRate xScaleFactor = tAxisLength * tStepMsec / self.tScale yScaleFactor = -(2.0 * yAxisLength) / 3.3 yOffset = self.frameList[self.numFramesIndex[ self.selectedPort]][j].bottom() # build waveform for i in range(length): polyline[i + 1] = QPointF( xScaleFactor * i + xOffset, yScaleFactor * self.signalProcessor.boardAdc[channel][i] + yOffset) # join to old waveform if self.tPosition == 0.0: polyline[0] = polyline[1] else: polyline[0] = QPointF( xScaleFactor * -1 + xOffset, yScaleFactor * self.plotDataOld[ j + self.topLeftFrame[self.selectedPort]] + yOffset) # save last point in waveform to join to next segment self.plotDataOld[j + self.topLeftFrame[ self.selectedPort]] = self.signalProcessor.boardAdc[ channel][length - 1] # draw waveform painter.setPen(Qt.darkGreen) if self.pointPlotMode: painter.drawPoints(QPolygonF(polyline)) else: painter.drawPolyline(QPolygonF(polyline)) elif stype == constants.BoardDigInSignal: # Plot USB interface board digital input signal tStepMsec = 1000.0 / self.sampleRate xScaleFactor = tAxisLength * tStepMsec / self.tScale yScaleFactor = -(2.0 * yAxisLength) / 2.0 yOffset = (self.frameList[self.numFramesIndex[ self.selectedPort]][j].bottom() + self.frameList[self.numFramesIndex[ self.selectedPort]][j].center().y()) / 2.0 # build waveform for i in range(length): polyline[i + 1] = QPointF( xScaleFactor * i + xOffset, yScaleFactor * self.signalProcessor.boardDigIn[channel][i] + yOffset) # join to old waveform if self.tPosition == 0.0: polyline[0] = polyline[1] else: polyline[0] = QPointF( xScaleFactor * -1 + xOffset, yScaleFactor * self.plotDataOld[ j + self.topLeftFrame[self.selectedPort]] + yOffset) # save last point in waveform to join to next segment self.plotDataOld[j + self.topLeftFrame[ self.selectedPort]] = self.signalProcessor.boardDigIn[ channel][length - 1] # draw waveform pen = QPen() pen.setColor(QColor(200, 50, 200)) painter.setPen(pen) if self.pointPlotMode: painter.drawPoints(QPolygonF(polyline)) else: painter.drawPolyline(QPolygonF(polyline)) painter.setClipping(False) tStepMsec = 1000.0 / self.sampleRate self.tPosition += length * tStepMsec if self.tPosition >= self.tScale: self.tPosition = 0.0
def paintEvent(self, event): # init menustyle = kikka.core.getGhost(self.gid).getMenuStyle() self._bg_image = menustyle.bg_image self._fg_image = menustyle.fg_image self._side_image = menustyle.side_image self.updateActionRect() p = QPainter(self) # draw background p.fillRect(QRect(QPoint(), self.size()), self._side_image.pixelColor(0, 0)) vertical = False y = self.height() while y > 0: yy = y - self._bg_image.height() p.drawImage(0, yy, self._side_image.mirrored(False, vertical)) x = self._side_image.width() while x < self.width(): p.drawImage(x, yy, self._bg_image.mirrored(False, vertical)) x += self._bg_image.width() p.drawImage(x, yy, self._bg_image.mirrored(True, vertical)) x += self._bg_image.width() + 1 y -= self._bg_image.height() vertical = not vertical # draw item actioncount = len(self.actions()) for i in range(actioncount): act = self.actions()[i] arect = QRect(self._aRect[i]) if event.rect().intersects(arect) is False: continue opt = QStyleOptionMenuItem() self.initStyleOption(opt, act) opt.rect = arect if opt.state & QStyle.State_Selected \ and opt.state & QStyle.State_Enabled: # Selected Item, draw foreground image p.setClipping(True) p.setClipRect(arect.x() + self._side_image.width(), arect.y(), self.width() - self._side_image.width(), arect.height()) p.fillRect(QRect(QPoint(), self.size()), self._fg_image.pixelColor(0, 0)) vertical = False y = self.height() while y > 0: x = self._side_image.width() while x < self.width(): yy = y - self._fg_image.height() p.drawImage(x, yy, self._fg_image.mirrored(False, vertical)) x += self._fg_image.width() p.drawImage(x, yy, self._fg_image.mirrored(True, vertical)) x += self._fg_image.width() + 1 y -= self._fg_image.height() vertical = not vertical p.setClipping(False) if opt.menuItemType == QStyleOptionMenuItem.Separator: # Separator p.setPen(menustyle.getPenColor(opt)) y = int(arect.y() + arect.height() / 2) p.drawLine(self._side_image.width(), y, arect.width(), y) else: # MenuItem self.drawControl(p, opt, arect, act.icon(), menustyle) pass # exit for
def paintEvent(self, event): unused(event) compassAIIntrusion = 0 compassHalfSpan = 180 painter = QPainter() painter.begin(self) painter.setRenderHint(QPainter.Antialiasing, True) painter.setRenderHint(QPainter.HighQualityAntialiasing, True) tapeGaugeWidth = self.tapesGaugeWidthFor(self.width(), self.width()) aiheight = self.height() aiwidth = self.width() - tapeGaugeWidth * 2 if (aiheight > aiwidth): aiheight = aiwidth AIMainArea = QRectF(tapeGaugeWidth, 0, aiwidth, aiheight) AIPaintArea = QRectF(0, 0, self.width(), self.height()) velocityMeterArea = QRectF(0, 0, tapeGaugeWidth, aiheight) altimeterArea = QRectF(AIMainArea.right(), 0, tapeGaugeWidth, aiheight) # calc starts compassRelativeWidth = 0.75 compassBottomMargin = 0.78 compassSize = compassRelativeWidth * AIMainArea.width( ) # Diameter is this times the width. compassCenterY = AIMainArea.bottom() + compassSize / 4 if self.height( ) - compassCenterY > AIMainArea.width() / 2 * compassBottomMargin: compassCenterY = self.height( ) - AIMainArea.width() / 2 * compassBottomMargin compassCenterY = (compassCenterY * 2 + AIMainArea.bottom() + compassSize / 4) / 3 compassArea = QRectF( AIMainArea.x() + (1 - compassRelativeWidth) / 2 * AIMainArea.width(), compassCenterY - compassSize / 2, compassSize, compassSize) if self.height() - compassCenterY < compassSize / 2: compassHalfSpan = math.acos( (compassCenterY - self.height()) * 2 / compassSize) * 180 / math.pi + self.COMPASS_DISK_RESOLUTION if compassHalfSpan > 180: compassHalfSpan = 180 compassAIIntrusion = compassSize / 2 + AIMainArea.bottom( ) - compassCenterY if compassAIIntrusion < 0: compassAIIntrusion = 0 #calc ends hadClip = painter.hasClipping() painter.setClipping(True) painter.setClipRect(AIPaintArea) self.drawAIGlobalFeatures(painter, AIMainArea, AIPaintArea) self.drawAIAttitudeScales(painter, AIMainArea, compassAIIntrusion) self.drawAIAirframeFixedFeatures(painter, AIMainArea) self.drawAICompassDisk(painter, compassArea, compassHalfSpan) painter.setClipping(hadClip) if self.isGPSAltitudePrimary: self.drawAltimeter(painter, altimeterArea, self.GPSAltitude, self.primaryAltitude, self.verticalVelocity) else: self.drawAltimeter(painter, altimeterArea, self.primaryAltitude, self.GPSAltitude, self.verticalVelocity) if self.isGPSSpeedPrimary: self.drawVelocityMeter(painter, velocityMeterArea, self.groundspeed, self.primarySpeed) else: self.drawVelocityMeter(painter, velocityMeterArea, self.primarySpeed, self.groundspeed) painter.end()
def paintEvent(self, event): if self.fScene is None: QFrame.paintEvent(self, event) return painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing, bool(options.antialiasing == ANTIALIASING_FULL)) # Brightness-aware out-of-canvas shading bg_color = self.fViewBg bg_black = bg_color.black() bg_shade = -12 if bg_black < 127 else 12 r, g, b, _ = bg_color.getRgb() bg_color = QColor(r + bg_shade, g + bg_shade, b + bg_shade) frameWidth = self.fFrameWidth if self.fUseCustomPaint: # Inner shadow color = QColor.fromHsv(40, 0, 255 - max(210, bg_color.black(), bg_black)) painter.setBrush(Qt.transparent) painter.setPen(color) painter.drawRect( QRectF(0.5, 0.5, self.width() - 1, self.height() - 1)) # Background painter.setBrush(bg_color) painter.setPen(bg_color) painter.drawRect( QRectF(1.5, 1.5, self.width() - 3, self.height() - 3)) else: use_rounding = int(frameWidth > 1) rounding = 0.5 * use_rounding painter.setBrush(bg_color) painter.setPen(bg_color) painter.drawRoundedRect( QRectF(0.5 + frameWidth, 0.5 + frameWidth, self.width() - 1 - frameWidth * 2, self.height() - 1 - frameWidth * 2), rounding, rounding) clipPath = QPainterPath() rounding = 1.0 * use_rounding clipPath.addRoundedRect( QRectF(frameWidth, frameWidth, self.width() - frameWidth * 2, self.height() - frameWidth * 2), rounding, rounding) painter.setClipPath(clipPath) self.fScene.render(painter, self.fRenderTarget, self.fRenderSource, Qt.KeepAspectRatio) # Allow cursor frame to look joined with minicanvas frame painter.setClipping(False) width = self.fViewRect[self._kRectWidth] / self.fScale height = self.fViewRect[self._kRectHeight] / self.fScale # cursor lineHinting = self.fViewPen.widthF() / 2 x = self.fViewRect[self._kRectX] + self.fInitialX y = self.fViewRect[self._kRectY] + self.fInitialY scr_x = floor(x) scr_y = floor(y) rect = QRectF(scr_x + lineHinting, scr_y + lineHinting, ceil(width + x - scr_x) - lineHinting * 2, ceil(height + y - scr_y) - lineHinting * 2) if self.fRubberBandBlending == self._RUBBERBAND_BLENDING_PLUS: painter.setCompositionMode(QPainter.CompositionMode_Plus) elif self.fRubberBandBlending == self._RUBBERBAND_BLENDING_DIFF: painter.setCompositionMode(QPainter.CompositionMode_Difference) painter.setBrush(self.fViewBrush) painter.setPen(Qt.NoPen) painter.drawRect(rect) painter.setCompositionMode(QPainter.CompositionMode_SourceOver) painter.setBrush(Qt.NoBrush) painter.setPen(self.fViewPen) painter.drawRect(rect) if self.fUseCustomPaint: event.accept() else: QFrame.paintEvent(self, event)
def updateSpikePlot(self, rms): tScale = 3.0 # time scale = 3.0 ms colorIndex = 2 if self.maxNumSpikeWaveforms == 10: colorIndex = 0 elif self.maxNumSpikeWaveforms == 20: colorIndex = 1 elif self.maxNumSpikeWaveforms == 30: colorIndex = 2 self.drawAxisLines() if self.pixmap is None: painter = QPainter() else: painter = QPainter(self.pixmap) # Vector for waveform plot points polyline = [0] * self.totalTSteps yAxisLength = (self.frame.height() - 2) / 2.0 tAxisLength = self.frame.width() - 1 xOffset = self.frame.left() + 1 # Set clipping region for plotting. adjustedFrame = copy(self.frame) adjustedFrame.adjust(0, 1, 0, 0) painter.setClipRect(adjustedFrame) xScaleFactor = tAxisLength * self.tStepMsec / tScale yScaleFactor = -yAxisLength / self.yScale yOffset = self.frame.center().y() index = self.maxNumSpikeWaveforms - self.numSpikeWaveforms for j in range(self.spikeWaveformIndex - self.numSpikeWaveforms, self.spikeWaveformIndex): # Build waveform for i in range(self.totalTSteps): polyline[i] = QPointF( xScaleFactor * i + xOffset, yScaleFactor * self.spikeWaveform[(j + 30) % len(self.spikeWaveform)][i] + yOffset) # Draw waveform painter.setPen(self.scopeColors[colorIndex][index]) index += 1 painter.drawPolyline(QPolygonF(polyline)) # If using a voltage threshold trigger, plot a line at the threshold level. if self.voltageTriggerMode: painter.setPen(Qt.red) painter.drawLine(xOffset, yScaleFactor * self.voltageThreshold + yOffset, xScaleFactor * (self.totalTSteps - 1) + xOffset, yScaleFactor * self.voltageThreshold + yOffset) painter.setClipping(False) # Don't update the RMS value display every time, or it will change so fast that it # will be hard to read. Only update once every few times we execute this function. if self.rmsDisplayPeriod == 0: self.rmsDisplayPeriod = 5 self.savedRms = rms else: self.rmsDisplayPeriod -= 1 # Write RMS value to display. textBoxWidth = 180 textBoxHeight = painter.fontMetrics().height() painter.setPen(Qt.darkGreen) if self.savedRms < 10.0: precision = "1" else: precision = "0" painter.drawText( self.frame.left() + 6, self.frame.top() + 5, textBoxWidth, textBoxHeight, Qt.AlignLeft | Qt.AlignTop, "RMS:" + ("%." + precision + "f") % self.savedRms + " " + constants.QSTRING_MU_SYMBOL + "V") self.update()
class PoincareViewModel(QWidget): def __init__(self, parent): super().__init__() self.parent = parent self.centerVertices = [] self.origin = QPointF() self.drawnTiles = defaultdict(defaultdict) self.tiles = [] self.tilesToUpdate = False self.sideCount = 5 self.adjacentCount = 4 self.renderDepth = 4 self.fillMode = True #Formula to calculate distance from center of disk to any vertex of the #initial polygon is from: #http://www.malinc.se/math/noneuclidean/poincaretilingen.php def getCenterVertices(self): p = self.sideCount q = self.adjacentCount dist = (self.diskDiameter/2) * math.sqrt(math.cos(math.pi * (1/p + 1/q)) / math.cos(math.pi * (1/p - 1/q))) alpha = 2*math.pi/p centerVertices = [] for i in range(p): x = self.origin.x() + (dist) * math.cos(i * alpha) y = self.origin.y() + (dist) * math.sin(i * alpha) centerVertices.append(QPointF(x, y)) return centerVertices #Since tiles are indexed by their centers (floating point), we need some leeway #with how 'close' two points need to be to be considered the same def hasBeenDrawn(self, aPoint): precision = 1000 x = round(precision * aPoint.x())/precision y = round(precision * aPoint.y())/precision try: return self.drawnTiles[x][y] except: return None def addDrawnTile(self, aTile): precision = 1000 x = round(precision * aTile.center.x())/precision y = round(precision * aTile.center.y())/precision self.drawnTiles[x][y] = aTile # Breadth-first construction of tiles by reflection about each side, with the # initial tile centered on the origin. This viewmodel is passed to each tile # since the disk's origin and diskDiameter are needed to calculate the arcs that # make up the sides of a tile. def drawTiling(self): self.drawnCount = 0 self.drawnTiles.clear() self.tiles.clear() self.centerVertices.clear() centerTile = Tile(self.getCenterVertices(), self, self.renderDepth) self.addDrawnTile(centerTile) queue = [centerTile] while queue: curTile = queue.pop() curTile.draw(self.painter) self.tiles.append(curTile) if curTile.layer == 1: continue for edge in curTile.edges: #First reflect the center of the current tile to check if the reflected #tile has been drawn before reflectedCenter = edge.reflectPoint(curTile.center) neighbor = self.hasBeenDrawn(reflectedCenter) if neighbor is None: #draw and log the new tile reflectedVertices = edge.reflectTile(curTile) neighbor = Tile(reflectedVertices, self, curTile.layer-1, reflectedCenter) queue.insert(0, neighbor) self.addDrawnTile(neighbor) #construct the list of neighbors if neighbor not in curTile.neighbors: curTile.neighbors.append(neighbor) if curTile not in neighbor.neighbors: neighbor.neighbors.append(curTile) def paintEvent(self, anEvent): self.painter = QPainter(self) self.painter.setRenderHint(QPainter.Antialiasing, on=True) self.diskDiameter = min(self.size().width(), self.size().height()) - 10 self.origin.setX(self.size().width()/2) self.origin.setY(self.size().height()/2) self.painter.setPen(QPen(QColor(122, 0, 127, 255), 3)) radius = self.diskDiameter/2 x = self.origin.x() y = self.origin.y() diskRect = QRect(x - radius, y - radius, self.diskDiameter, self.diskDiameter) self.diskRegion = QRegion(diskRect, QRegion.Ellipse) self.painter.setClipRegion(self.diskRegion) if self.tilesToUpdate: for tile in self.tiles: tile.update(self.painter) self.tilesToUpdate = False else: self.drawTiling() self.painter.setClipping(False) self.painter.setPen(QPen(QColor(5, 0, 127, 255), 3)) self.painter.drawEllipse(diskRect) self.painter.drawPoint(self.origin) self.painter.end() def updateTiles(self): self.tilesToUpdate = True self.update() def areHyperbolicDims(self, p, q): return (p-2)*(q-2) > 4 def setSideCount(self, count): if self.areHyperbolicDims(count, self.adjacentCount): self.sideCount = count self.update() return 0 return -1 def setAdjCount(self, count): if self.areHyperbolicDims(self.sideCount, count): self.adjacentCount = count self.update() return 0 return -1 def setRenderDepth(self, depth): self.renderDepth = depth self.update() def mousePressEvent(self, e): if self.diskRegion.contains(QPoint(e.x(), e.y())): self.parent.controller.clicked(e) def toggleFillMode(self): self.fillMode = not self.fillMode self.update()