Example #1
0
	def updateMotionHeatmap(self) -> None:
		"""Repaint the motion heatmap when we enter this screen.
			
			We never record while on the playback screen, so we don't
			have to live-update here. This is partially due to the
			fact that the camera is modal around this, it can either
			record xor playback."""
		
		return #Heatmap got delayed. Just return for now…
		
		heatmapHeight = 16
		
		motionData = QByteArray.fromRawData(api.control('waterfallMotionMap', {'segment':'placeholder', 'startFrame':400})["heatmap"]) # 16×(n<1024) heatmap. motionData: {"startFrame": int, "endFrame": int, "heatmap": QByteArray}
		assert len(motionData) % heatmapHeight == 0, f"Incompatible heatmap size {len(motionData)}; must be a multiple of {heatmapHeight}."
		
		self.motionHeatmap = (
			QImage( #Rotated 90°, since the data is packed line-by-line. We'll draw it counter-rotated.
				heatmapHeight,
				len(motionData)//heatmapHeight,
				QImage.Format_Grayscale8)
			.transformed(QTransform().rotate(-90).scale(-1,1))
			.scaled(
				self.uiTimelineVisualization.width(),
				self.uiTimelineVisualization.height(),
				transformMode=QtCore.Qt.SmoothTransformation)
		)
		
		self.uiTimelineVisualization.update() #Invokes self.paintMotionHeatmap if needed.
Example #2
0
    def createPath(cls, x, y, fill=Qt.OddEvenFill):
        # https://code.woboq.org/qt5/qtbase/src/gui/painting/qpainterpath.cpp.html#_ZrsR11QDataStreamR12QPainterPath
        # http://doc.qt.io/qt-5/qpainterpath.html#ElementType-enum
        # http://doc.qt.io/qt-5/qt.html#FillRule-enum

        # QDataStream &QPainterPath::operator>>(QDataStream &s, QPainterPath &p)
        #      offset  size    type  description
        #           0     4   int32  element count (N)
        #           4     4   int32  element type (0 -- 3)
        #           8     8  double  x
        #          16     8  double  y
        #         ...
        #     20*i+ 4     4   int32  element type (0 -- 3)
        #     20*i+ 8     8  double  x
        #     20*i+16     8  double  y
        #         ...
        # 20*(N-1)+ 4     4   int32  element type (0 -- 3)
        # 20*(N-1)+ 8     8  double  x
        # 20*(N-1)+16     8  double  y
        # 20*(N-1)+20     4   int32  next starting i (N-1)
        # 20*(N-1)+24     4   int32  fill rule

        path = QPainterPath()

        N = x.shape[0]
        if N == 0:
            return path

        data = np.empty(N + 2,
                        dtype=[('type', '<i4'), ('x', '<f8'), ('y', '<f8')])
        data[1]['type'] = 0
        data[2:N + 1]['type'] = 1
        data[1:N + 1]['x'] = x
        data[1:N + 1]['y'] = y

        fpos = 20 * (N + 1)

        view = data.view(dtype=np.ubyte)
        view[:16] = 0
        view.data[16:20] = struct.pack('<i', N)
        view.data[fpos:fpos + 8] = struct.pack('<ii', N - 1, int(fill))

        buf = QByteArray.fromRawData(view.data[16:fpos + 8])
        ds = QDataStream(buf)
        ds.setByteOrder(ds.LittleEndian)

        ds >> path
        return path
Example #3
0
    def array2Path(x, y):
        """Convert array to QPainterPath."""
        path = QPainterPath()
        if len(x) >= 2:
            # see: https://github.com/qt/qtbase/blob/dev/src/gui/painting/qpainterpath.cpp
            n = len(x)
            buf = np.empty(n + 2,
                           dtype=[('c', '>i4'), ('x', '>f8'), ('y', '>f8')])
            byteview = buf.view(dtype=np.ubyte)
            # header (size)
            byteview[:16] = 0
            byteview.data[16:20] = struct.pack('>i', n)
            # data
            data = buf[1:-1]
            data['c'], data['x'], data['y'] = 1, x, y
            data['c'][0] = 0
            # tail (cStart, fillRule)
            byteview.data[-20:-16] = struct.pack('>i', 0)
            byteview.data[-16:-12] = struct.pack('>i', 0)

            # take the pointer without copy
            arr = QByteArray.fromRawData(byteview.data[16:-12])
            QDataStream(arr) >> path
        return path