1import math
2
3import numpy as np
4from PyQt5.QtCore import QObject
5from PyQt5.QtGui import QPen, QColor
6from PyQt5.QtWidgets import QGraphicsPathItem
7from urh.signalprocessing.IQArray import IQArray
8
9from urh import settings
10from urh.cythonext import path_creator, util
11from urh.ui.painting.ZoomableScene import ZoomableScene
12
13
14class SceneManager(QObject):
15    def __init__(self, parent):
16        super().__init__(parent)
17        self.scene = ZoomableScene()
18        self.__plot_data = None  # type: np.ndarray
19        self.line_item = self.scene.addLine(0, 0, 0, 0, QPen(settings.AXISCOLOR, 0))
20
21    @property
22    def plot_data(self):
23        return self.__plot_data
24
25    @plot_data.setter
26    def plot_data(self, value):
27        self.__plot_data = value
28
29    @property
30    def num_samples(self):
31        return len(self.plot_data)
32
33    def show_scene_section(self, x1: float, x2: float, subpath_ranges=None, colors=None):
34        """
35
36        :param x1: start of section to show
37        :param x2: end of section to show
38        :param subpath_ranges: for coloring subpaths
39        :type subpath_ranges: list of tuple
40        :param colors: for coloring the subpaths
41        :type color: list of QColor
42        :return:
43        """
44        start, end = self.__limit_value(x1), self.__limit_value(x2)
45
46        if end > start:
47            paths = path_creator.create_path(self.plot_data, start=start, end=end,
48                                             subpath_ranges=subpath_ranges)
49            self.set_path(paths, colors=colors)
50
51    def set_path(self, paths: list, colors=None):
52        self.clear_path()
53        colors = [settings.LINECOLOR] * len(paths) if colors is None else colors
54        assert len(paths) == len(colors)
55        for path, color in zip(paths, colors):
56            path_object = self.scene.addPath(path, QPen(color if color else settings.LINECOLOR, 0))
57            if color:
58                path_object.setZValue(1)
59
60    def __limit_value(self, val: float) -> int:
61        return 0 if val < 0 else self.num_samples if val > self.num_samples else int(val)
62
63    def show_full_scene(self):
64        self.show_scene_section(0, self.num_samples)
65
66    def init_scene(self):
67        if self.num_samples == 0:
68            return
69
70        minimum, maximum = IQArray.min_max_for_dtype(self.plot_data.dtype)
71        self.scene.setSceneRect(0, minimum, self.num_samples, maximum - minimum)
72        self.scene.setBackgroundBrush(settings.BGCOLOR)
73
74        if self.line_item is not None:
75            self.line_item.setLine(0, 0, self.num_samples, 0)
76
77    def clear_path(self):
78        for item in self.scene.items():
79            if isinstance(item, QGraphicsPathItem):
80                self.scene.removeItem(item)
81                item.setParentItem(None)
82                del item
83
84    def eliminate(self):
85        self.plot_data = None
86        self.line_item = None
87        self.scene.clear()
88        self.scene.setParent(None)
89
90    @staticmethod
91    def create_rectangle(proto_bits, pulse_len=100):
92        """
93        :type proto_bits: list of str
94        """
95        ones = np.ones(pulse_len, dtype=np.float32) * 1
96        zeros = np.ones(pulse_len, dtype=np.float32) * -1
97        n = 0
98        y = []
99        for msg in proto_bits:
100            for bit in msg:
101                n += pulse_len
102                if bit == "0":
103                    y.extend(zeros)
104                else:
105                    y.extend(ones)
106        x = np.arange(0, n).astype(np.int64)
107        scene = ZoomableScene()
108        scene.setSceneRect(0, -1, n, 2)
109        scene.setBackgroundBrush(settings.BGCOLOR)
110        scene.addLine(0, 0, n, 0, QPen(settings.AXISCOLOR, 0))
111        if len(y) > 0:
112            y = np.array(y)
113        else:
114            y = np.array(y).astype(np.float32)
115        path = path_creator.array_to_QPath(x, y)
116        scene.addPath(path, QPen(settings.LINECOLOR, 0))
117        return scene, n
118