Ejemplo n.º 1
0
class KeyMonitor(QtCore.QObject):
    keyPressed = QtCore.pyqtSignal(object)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.listener = Listener(on_press=self.on_press, on_release=self.on_release)
        self.currentKey = None
        self.released = False
        print("Monitor init!")

    def on_press(self, key):
        self.released = False
        self.currentKey = key
        self.keyPressed.emit(key)

    def on_release(self, key):
        self.currentKey = None
        self.released = True

    def stop_monitoring(self):
        self.listener.stop()
        self.deleteLater()

    def start_monitoring(self):
        self.listener.start()
Ejemplo n.º 2
0
class LineText(QtWidgets.QLineEdit):
    update = QtCore.pyqtSignal(str, str)

    def __init__(self, parent):
        QtWidgets.QTextEdit.__init__(self, parent)
        self.timer = QtCore.QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.fire)

    def fire(self):
        self.update.emit(self.parent().objectName(), self.text())
        self.timer.stop()

    def keyPressEvent(self, event):
        if self.timer.isActive():
            self.timer.stop()
            self.timer.setInterval(1000)
            self.timer.start()
        else:
            self.timer.start()
        QtWidgets.QLineEdit.keyPressEvent(self, event)

    def load_data(self, data):
        key = self.parent().objectName()
        if key in data:
            self.setText(data[key])
Ejemplo n.º 3
0
class ButtonQLabel(QtWidgets.QLabel):
    # 自定义信号, 注意信号必须为类属性
    button_clicked_signal = QtCore.pyqtSignal()

    def mouseReleaseEvent(self, me):
        self.button_clicked_signal.emit()

    # 可在外部与槽函数连接
    def onclick(self, func):
        self.button_clicked_signal.connect(func)
class Mythread(QtCore.QThread):
    # 定义信号,定义参数为str类型
    signal_one = QtCore.pyqtSignal(int)

    def __init__(self, parent=None):
        super().__init__(parent)

    def run(self):
        test = HtmlParser("=")
        print("##########")
        pass
Ejemplo n.º 5
0
class KeysWidget(QWidget):
    keyPressed = QtCore.pyqtSignal(QtCore.QEvent)

    def __init__(self, parent=None):
        super(KeysWidget, self).__init__(parent)
        self.classifyExercises = None
        if parent is not None:
            self.classifyExercises = parent.classifyExercises
            self.infoLabel = parent.infoLabel

        self.ui = Ui_KeysPanel()
        self.ui.setupUi(self)
        self.monitor = KeyMonitor()
        self.monitor.start_monitoring()

        self.timer = QTimer()
        self.timer.timeout.connect(self.onTimeout)
        self.timer.start()

        self.ui.saveProfile.clicked.connect(self.saveBindings)

    def saveBindings(self):
        if self.classifyExercises.subject is not None:
            key_list = [x.serialize() for x in self.classifyExercises.exercises.values()]
            content = {
                self.classifyExercises.subject: key_list
            }
            print(content)
            with open(MAPPED_KEYS_PATH + self.classifyExercises.subject + '.json', "w") as f:
                json.dump(content, f)

    def onTimeout(self):
        if self.monitor.released:
            for b in self.ui.buttons:
                b.setStyleSheet(
                    """ QPushButton
                    {
                        border: 1px solid grey;
                        background-color: white;
                    }
                    """)
        else:
            for ind in range(0, len(self.ui.exercises)):
                if self.monitor.currentKey == self.ui.exercises[ind].assigned_key[1]:
                    self.ui.buttons[ind].setStyleSheet(
                    """ QPushButton
                    {
                        border: 1px solid green;
                        background-color: #7FFFD4;
                    }
                    """)
Ejemplo n.º 6
0
class TrainThread(QThread):
    taskFinished = QtCore.pyqtSignal()

    def __init__(self, classify: ClassifyExercises = None):
        QThread.__init__(self)
        self.classify = classify

    # def __del__(self):
    #     self.wait()

    def run(self):
        # your logic here
        self.classify.TrainEMG()
        self.taskFinished.emit()
Ejemplo n.º 7
0
class RecordThread(QThread):
    taskFinished = QtCore.pyqtSignal()

    def __init__(self,
                 classify: ClassifyExercises = None,
                 exercise: str = None):
        QThread.__init__(self)
        self.classify = classify
        self.exercise = exercise
        self.result = None

    def run(self):
        # your logic here
        result = self.classify.RecordExercise(self.exercise)
        self.taskFinished.emit()
        self.result = result
Ejemplo n.º 8
0
class ExceptionHandler(QtCore.QObject):
    exception = QtCore.pyqtSignal(list)

    def __init__(self):
        QtCore.QObject.__init__(self)
        sys.excepthook = self.handle_exception

    def handle_exception(self, ex_type, ex_value, ex_traceback):
        error = []
        error.append(ex_type.__name__)
        for line in traceback.format_tb(ex_traceback):
            error.append(line)
        self.exception.emit(error)

        if DEBUG:
            for line in error:
                print(line)
Ejemplo n.º 9
0
class MetaboliteSimulation(QtCore.QObject):

    postToConsole = QtCore.pyqtSignal(str)
    outputResults = QtCore.pyqtSignal(object)
    finished = QtCore.pyqtSignal(int)

    def __init__(self, thread_num, insysfile, sim_experiment):

        QtCore.QObject.__init__(self)

        self.thread_num = thread_num
        self.insysfile = insysfile
        self.sim_experiment = sim_experiment

    def simulate(self):
        self.postToConsole.emit('   | Simulating ... ' + self.insysfile)
        print('    | Simulating ...' + self.insysfile)

        metab_name = self.insysfile.replace('.sys', '')

        if self.sim_experiment.b0 == 123.3:
            self.insysfile = 'pints/metabolites/3T_' + self.insysfile
        elif self.sim_experiment.b0 == 297.2:
            self.insysfile = 'pints/metabolites/7T_' + self.insysfile
        elif self.sim_experiment.b0 == 400.2:
            self.insysfile = 'pints/metabolites/9.4T_' + self.insysfile

        if self.sim_experiment.name == "semi-LASER (Bruker)":
            spin_system = pg.spin_system()
            spin_system.read(self.insysfile)
            for i in range(spin_system.spins()):
                spin_system.PPM(
                    i,
                    spin_system.PPM(i) - self.sim_experiment.RF_OFFSET)

            TE = self.sim_experiment.TE * 1E-3
            TE1 = self.sim_experiment.TE1 * 1E-3
            TE2 = self.sim_experiment.TE2 * 1E-3

            # build 90 degree pulse
            inpulse90file = self.sim_experiment.inpulse90file
            A_90 = self.sim_experiment.A_90
            PULSE_90_LENGTH = self.sim_experiment.PULSE_90_LENGTH
            gyratio = self.sim_experiment.getGyratio()

            pulse90 = Pulse(inpulse90file, PULSE_90_LENGTH, 'bruker')

            n_old = np.linspace(0, PULSE_90_LENGTH, sp.size(pulse90.waveform))
            n_new = np.linspace(0, PULSE_90_LENGTH,
                                sp.size(pulse90.waveform) + 1)

            waveform_real = sp.interpolate.InterpolatedUnivariateSpline(
                n_old,
                np.real(pulse90.waveform) * A_90)(n_new)
            waveform_imag = sp.interpolate.InterpolatedUnivariateSpline(
                n_old,
                np.imag(pulse90.waveform) * A_90)(n_new)
            pulse90.waveform = waveform_real + 1j * (waveform_imag)

            ampl_arr = np.abs(pulse90.waveform)
            phas_arr = np.unwrap(np.angle(pulse90.waveform)) * 180.0 / math.pi

            pulse = pg.row_vector(len(pulse90.waveform))
            ptime = pg.row_vector(len(pulse90.waveform))
            for j, val in enumerate(zip(ampl_arr, phas_arr)):
                pulse.put(pg.complex(val[0], val[1]), j)
                ptime.put(pg.complex(pulse90.pulsestep, 0), j)

            pulse_dur_90 = pulse.size() * pulse90.pulsestep
            pwf_90 = pg.PulWaveform(pulse, ptime, "90excite")
            pulc_90 = pg.PulComposite(pwf_90, spin_system,
                                      self.sim_experiment.obs_iso)

            Ureal90 = pulc_90.GetUsum(-1)

            # build 180 degree pulse
            inpulse180file = self.sim_experiment.inpulse180file
            A_180 = self.sim_experiment.A_180
            PULSE_180_LENGTH = self.sim_experiment.PULSE_180_LENGTH
            gyratio = self.sim_experiment.getGyratio()

            pulse180 = Pulse(inpulse180file, PULSE_180_LENGTH, 'bruker')

            n_old = np.linspace(0, PULSE_180_LENGTH,
                                sp.size(pulse180.waveform))
            n_new = np.linspace(0, PULSE_180_LENGTH,
                                sp.size(pulse180.waveform) + 1)

            waveform_real = sp.interpolate.InterpolatedUnivariateSpline(
                n_old,
                np.real(pulse180.waveform) * A_180)(n_new)
            waveform_imag = sp.interpolate.InterpolatedUnivariateSpline(
                n_old,
                np.imag(pulse180.waveform) * A_180)(n_new)
            pulse180.waveform = waveform_real + 1j * (waveform_imag)

            ampl_arr = np.abs(pulse180.waveform)
            phas_arr = np.unwrap(np.angle(pulse180.waveform)) * 180.0 / math.pi
            freq_arr = np.gradient(phas_arr)

            pulse = pg.row_vector(len(pulse180.waveform))
            ptime = pg.row_vector(len(pulse180.waveform))
            for j, val in enumerate(zip(ampl_arr, phas_arr)):
                pulse.put(pg.complex(val[0], val[1]), j)
                ptime.put(pg.complex(n_new[1], 0), j)

            pulse_dur_180 = pulse.size() * pulse180.pulsestep
            pwf_180 = pg.PulWaveform(pulse, ptime, "180afp")
            pulc_180 = pg.PulComposite(pwf_180, spin_system,
                                       self.sim_experiment.obs_iso)

            Ureal180 = pulc_180.GetUsum(-1)

            H = pg.Hcs(spin_system) + pg.HJ(spin_system)
            D = pg.Fm(spin_system, self.sim_experiment.obs_iso)
            ac = pg.acquire1D(pg.gen_op(D), H, self.sim_experiment.dwell_time)
            ACQ = ac

            delay1 = TE1 / 2.0 - pulse_dur_90 / 2.0 - pulse_dur_180 / 2.0
            delay2 = TE1 / 2.0 + TE2 / 2.0 - pulse_dur_180
            delay3 = TE2 - pulse_dur_180
            delay4 = delay2
            delay5 = TE1 / 2.0 - pulse_dur_180 + self.sim_experiment.DigShift

            Udelay1 = pg.prop(H, delay1)
            Udelay2 = pg.prop(H, delay2)
            Udelay3 = pg.prop(H, delay3)
            Udelay4 = pg.prop(H, delay4)
            Udelay5 = pg.prop(H, delay5)

            sigma0 = pg.sigma_eq(spin_system)  # init
            sigma1 = Ureal90.evolve(sigma0)  # apply 90-degree pulse
            sigma0 = pg.evolve(sigma1, Udelay1)
            sigma1 = Ureal180.evolve(sigma0)  # apply AFP1
            sigma0 = pg.evolve(sigma1, Udelay2)
            sigma1 = Ureal180.evolve(sigma0)  # apply AFP2
            sigma0 = pg.evolve(sigma1, Udelay3)
            sigma1 = Ureal180.evolve(sigma0)  # apply AFP3
            sigma0 = pg.evolve(sigma1, Udelay4)
            sigma1 = Ureal180.evolve(sigma0)  # apply AFP4
            sigma0 = pg.evolve(sigma1, Udelay5)

        elif self.sim_experiment.name == "semi-LASER":
            spin_system = pg.spin_system()
            spin_system.read(self.insysfile)
            for i in range(spin_system.spins()):
                spin_system.PPM(
                    i,
                    spin_system.PPM(i) - self.sim_experiment.RF_OFFSET)

            TE = self.sim_experiment.TE
            TE1 = float((TE * 0.31) / 1000.0)
            TE3 = float((TE * 0.31) / 1000.0)
            TE2 = float(TE / 1000.0 - TE1 - TE3)
            TE_fill = TE / 1000.0 - TE1 - TE2 - TE3

            # build 90 degree pulse
            inpulse90file = self.sim_experiment.inpulse90file
            A_90 = self.sim_experiment.A_90
            PULSE_90_LENGTH = self.sim_experiment.PULSE_90_LENGTH
            gyratio = self.sim_experiment.getGyratio()

            pulse90 = Pulse(inpulse90file, PULSE_90_LENGTH)

            n_old = np.linspace(0, PULSE_90_LENGTH, sp.size(pulse90.waveform))
            n_new = np.linspace(0, PULSE_90_LENGTH,
                                sp.size(pulse90.waveform) + 1)

            waveform_real = sp.interpolate.InterpolatedUnivariateSpline(
                n_old,
                np.real(pulse90.waveform) * A_90)(n_new)
            waveform_imag = sp.interpolate.InterpolatedUnivariateSpline(
                n_old,
                np.imag(pulse90.waveform) * A_90)(n_new)
            pulse90.waveform = waveform_real + 1j * (waveform_imag)

            ampl_arr = np.abs(pulse90.waveform) * gyratio
            phas_arr = np.unwrap(np.angle(pulse90.waveform)) * 180.0 / math.pi

            pulse = pg.row_vector(len(pulse90.waveform))
            ptime = pg.row_vector(len(pulse90.waveform))
            for j, val in enumerate(zip(ampl_arr, phas_arr)):
                pulse.put(pg.complex(val[0], val[1]), j)
                ptime.put(pg.complex(pulse90.pulsestep, 0), j)

            pulse_dur_90 = pulse.size() * pulse90.pulsestep
            peak_to_end_90 = pulse_dur_90 - (
                209 + self.sim_experiment.fudge_factor) * pulse90.pulsestep
            pwf_90 = pg.PulWaveform(pulse, ptime, "90excite")
            pulc_90 = pg.PulComposite(pwf_90, spin_system,
                                      self.sim_experiment.obs_iso)

            Ureal90 = pulc_90.GetUsum(-1)

            # build 180 degree pulse
            inpulse180file = self.sim_experiment.inpulse180file
            A_180 = self.sim_experiment.A_180
            PULSE_180_LENGTH = self.sim_experiment.PULSE_180_LENGTH
            gyratio = self.sim_experiment.getGyratio()

            pulse180 = Pulse(inpulse180file, PULSE_180_LENGTH)

            n_old = np.linspace(0, PULSE_180_LENGTH,
                                sp.size(pulse180.waveform))
            n_new = np.linspace(0, PULSE_180_LENGTH,
                                sp.size(pulse180.waveform) + 1)

            waveform_real = sp.interpolate.InterpolatedUnivariateSpline(
                n_old,
                np.real(pulse180.waveform) * A_180)(n_new)
            waveform_imag = sp.interpolate.InterpolatedUnivariateSpline(
                n_old,
                np.imag(pulse180.waveform) * A_180)(n_new)
            pulse180.waveform = waveform_real + 1j * (waveform_imag)

            ampl_arr = np.abs(pulse180.waveform) * gyratio
            phas_arr = np.unwrap(np.angle(pulse180.waveform)) * 180.0 / math.pi
            freq_arr = np.gradient(phas_arr)

            pulse = pg.row_vector(len(pulse180.waveform))
            ptime = pg.row_vector(len(pulse180.waveform))
            for j, val in enumerate(zip(ampl_arr, phas_arr)):
                pulse.put(pg.complex(val[0], val[1]), j)
                ptime.put(pg.complex(n_new[1], 0), j)

            pulse_dur_180 = pulse.size() * pulse180.pulsestep
            pwf_180 = pg.PulWaveform(pulse, ptime, "180afp")
            pulc_180 = pg.PulComposite(pwf_180, spin_system,
                                       self.sim_experiment.obs_iso)

            Ureal180 = pulc_180.GetUsum(-1)

            H = pg.Hcs(spin_system) + pg.HJ(spin_system)
            D = pg.Fm(spin_system, self.sim_experiment.obs_iso)
            ac = pg.acquire1D(pg.gen_op(D), H, self.sim_experiment.dwell_time)
            ACQ = ac

            delay1 = TE1 / 2.0 + TE_fill / 8.0 - pulse_dur_180 / 2.0 - peak_to_end_90
            delay2 = TE1 / 2.0 + TE_fill / 8.0 + TE2 / 4.0 + TE_fill / 8.0 - pulse_dur_180
            delay3 = TE2 / 4.0 + TE_fill / 8.0 + TE2 / 4.0 + TE_fill / 8.0 - pulse_dur_180
            delay4 = TE2 / 4.0 + TE_fill / 8.0 + TE3 / 2.0 + TE_fill / 8.0 - pulse_dur_180
            delay5 = TE3 / 2.0 + TE_fill / 8.0 - pulse_dur_180 / 2.0

            Udelay1 = pg.prop(H, delay1)
            Udelay2 = pg.prop(H, delay2)
            Udelay3 = pg.prop(H, delay3)
            Udelay4 = pg.prop(H, delay4)
            Udelay5 = pg.prop(H, delay5)

            sigma0 = pg.sigma_eq(spin_system)  # init
            sigma1 = Ureal90.evolve(sigma0)  # apply 90-degree pulse
            sigma0 = pg.evolve(sigma1, Udelay1)
            sigma1 = Ureal180.evolve(sigma0)  # apply AFP1
            sigma0 = pg.evolve(sigma1, Udelay2)
            sigma1 = Ureal180.evolve(sigma0)  # apply AFP2
            sigma0 = pg.evolve(sigma1, Udelay3)
            sigma1 = Ureal180.evolve(sigma0)  # apply AFP3
            sigma0 = pg.evolve(sigma1, Udelay4)
            sigma1 = Ureal180.evolve(sigma0)  # apply AFP4
            sigma0 = pg.evolve(sigma1, Udelay5)

        elif self.sim_experiment.name == "LASER":
            spin_system = pg.spin_system()
            spin_system.read(self.insysfile)
            for i in range(spin_system.spins()):
                spin_system.PPM(
                    i,
                    spin_system.PPM(i) - self.sim_experiment.RF_OFFSET)

            # build 90 degree AHP pulse
            inpulse90file = self.sim_experiment.inpulse90file
            A_90 = self.sim_experiment.A_90
            PULSE_90_LENGTH = self.sim_experiment.PULSE_90_LENGTH
            gyratio = self.sim_experiment.getGyratio()

            pulse90 = Pulse(inpulse90file, PULSE_90_LENGTH, 'varian')

            n_new = np.linspace(0, PULSE_90_LENGTH, 256)

            waveform_real = np.real(pulse90.waveform) * A_90
            waveform_imag = np.imag(pulse90.waveform) * A_90
            pulse90.waveform = waveform_real + 1j * (waveform_imag)

            ampl_arr = np.abs(pulse90.waveform) * gyratio
            phas_arr = np.unwrap(np.angle(pulse90.waveform)) * 180.0 / math.pi

            pulse = pg.row_vector(len(pulse90.waveform))
            ptime = pg.row_vector(len(pulse90.waveform))
            for j, val in enumerate(zip(ampl_arr, phas_arr)):
                pulse.put(pg.complex(val[0], val[1]), j)
                ptime.put(pg.complex(pulse90.pulsestep, 0), j)

            pulse_dur_90 = pulse.size() * pulse90.pulsestep
            pwf_90 = pg.PulWaveform(pulse, ptime, "90excite")
            pulc_90 = pg.PulComposite(pwf_90, spin_system,
                                      self.sim_experiment.obs_iso)

            Ureal90 = pulc_90.GetUsum(-1)

            # build 180 degree pulse
            inpulse180file = self.sim_experiment.inpulse180file
            A_180 = self.sim_experiment.A_180
            PULSE_180_LENGTH = self.sim_experiment.PULSE_180_LENGTH
            gyratio = self.sim_experiment.getGyratio()

            pulse180 = Pulse(inpulse180file, PULSE_180_LENGTH, 'varian')

            n_new = np.linspace(0, PULSE_180_LENGTH, 512)

            waveform_real = np.real(pulse180.waveform) * A_180
            waveform_imag = np.imag(pulse180.waveform) * A_180
            pulse180.waveform = waveform_real + 1j * (waveform_imag)

            ampl_arr = np.abs(pulse180.waveform) * gyratio
            phas_arr = np.unwrap(np.angle(pulse180.waveform)) * 180.0 / math.pi
            freq_arr = np.gradient(phas_arr)

            pulse = pg.row_vector(len(pulse180.waveform))
            ptime = pg.row_vector(len(pulse180.waveform))
            for j, val in enumerate(zip(ampl_arr, phas_arr)):
                pulse.put(pg.complex(val[0], val[1]), j)
                ptime.put(pg.complex(n_new[1], 0), j)

            pulse_dur_180 = pulse.size() * pulse180.pulsestep
            pwf_180 = pg.PulWaveform(pulse, ptime, "180afp")
            pulc_180 = pg.PulComposite(pwf_180, spin_system,
                                       self.sim_experiment.obs_iso)

            Ureal180 = pulc_180.GetUsum(-1)

            # calculate pulse timings
            ROF1 = 100E-6  #sec
            ROF2 = 10E-6  #sec
            TCRUSH1 = 0.0008  #sec
            TCRUSH2 = 0.0008  #sec

            ss_grad_rfDelayFront = 0  #TCRUSH1 - ROF1
            ss_grad_rfDelayBack = 0  #TCRUSH2 - ROF2
            ro_grad_atDelayFront = 0
            ro_grad_atDelayBack = 0

            TE = self.sim_experiment.TE / 1000.
            ipd = (TE - pulse_dur_90 \
                - 6*(ss_grad_rfDelayFront + pulse_dur_180 + ss_grad_rfDelayBack) \
                - ro_grad_atDelayFront) / 12

            delay1 = ipd + ss_grad_rfDelayFront
            delay2 = ss_grad_rfDelayBack + 2 * ipd + ss_grad_rfDelayFront
            delay3 = ss_grad_rfDelayBack + 2 * ipd + ss_grad_rfDelayFront
            delay4 = ss_grad_rfDelayBack + 2 * ipd + ss_grad_rfDelayFront
            delay5 = ss_grad_rfDelayBack + 2 * ipd + ss_grad_rfDelayFront
            delay6 = ss_grad_rfDelayBack + 2 * ipd + ss_grad_rfDelayFront
            delay7 = ss_grad_rfDelayBack + ipd + ro_grad_atDelayFront

            # print A_90, A_180, pulse_dur_90, pulse_dur_180
            # print TE, ipd, pulse_dur_90+6*pulse_dur_180, delay1+delay2+delay3+delay4+delay5+delay6+delay7, pulse_dur_90+6*pulse_dur_180+delay1+delay2+delay3+delay4+delay5+delay6+delay7
            # print ''

            # initialize acquisition
            H = pg.Hcs(spin_system) + pg.HJ(spin_system)
            D = pg.Fm(spin_system, self.sim_experiment.obs_iso)
            ac = pg.acquire1D(pg.gen_op(D), H, self.sim_experiment.dwell_time)
            ACQ = ac

            Udelay1 = pg.prop(H, delay1)
            Udelay2 = pg.prop(H, delay2)
            Udelay3 = pg.prop(H, delay3)
            Udelay4 = pg.prop(H, delay4)
            Udelay5 = pg.prop(H, delay5)
            Udelay6 = pg.prop(H, delay6)
            Udelay7 = pg.prop(H, delay7)

            sigma0 = pg.sigma_eq(spin_system)  # init
            sigma1 = Ureal90.evolve(sigma0)  # apply 90-degree pulse
            sigma0 = pg.evolve(sigma1, Udelay1)
            sigma1 = Ureal180.evolve(sigma0)  # apply AFP1
            sigma0 = pg.evolve(sigma1, Udelay2)
            sigma1 = Ureal180.evolve(sigma0)  # apply AFP2
            sigma0 = pg.evolve(sigma1, Udelay3)
            sigma1 = Ureal180.evolve(sigma0)  # apply AFP3
            sigma0 = pg.evolve(sigma1, Udelay4)
            sigma1 = Ureal180.evolve(sigma0)  # apply AFP4
            sigma0 = pg.evolve(sigma1, Udelay5)
            sigma1 = Ureal180.evolve(sigma0)  # apply AFP5
            sigma0 = pg.evolve(sigma1, Udelay6)
            sigma1 = Ureal180.evolve(sigma0)  # apply AFP6
            sigma0 = pg.evolve(sigma1, Udelay7)

        # acquire
        mx = pg.TTable1D(ACQ.table(sigma0))

        # binning to remove degenerate peaks

        # BINNING
        # Note: Metabolite Peak Normalization and Blending

        # The transition tables calculated by the GAMMA density matrix simulations frequently contain a
        # large number of transitions caused by degenerate splittings and other processes. At the
        # conclusion of each simulation run a routine is called to extract lines from the transition table.
        # These lines are then normalized using a closed form calculation based on the number of spins.
        # To reduce the number of lines required for display, multiple lines are blended by binning them
        # together based on their PPM locations and phases. The following parameters are used to
        # customize these procedures:

        # Peak Search Range -- Low/High (PPM): the range in PPM that is searched for lines from the
        # metabolite simulation.

        # Peak Blending Tolerance (PPM and Degrees): the width of the bins (+/- in PPM and +/- in
        # PhaseDegrees) that are used to blend the lines in the simulation. Lines that are included in the
        # same bin are summed using complex addition based on Amplitude and Phase.

        b0 = self.sim_experiment.b0
        obs_iso = self.sim_experiment.obs_iso
        tolppm = self.sim_experiment.tolppm
        tolpha = self.sim_experiment.tolpha
        ppmlo = self.sim_experiment.ppmlo
        ppmhi = self.sim_experiment.ppmhi
        rf_off = self.sim_experiment.RF_OFFSET

        field = b0
        nspins = spin_system.spins()

        nlines = mx.size()

        tmp = pg.Isotope(obs_iso)
        obs_qn = tmp.qn()

        qnscale = 1.0
        for i in range(nspins):
            qnscale *= 2 * spin_system.qn(i) + 1
        qnscale = qnscale / (2.0 * (2.0 * obs_qn + 1))

        freqs = []
        outf = []
        outa = []
        outp = []
        nbin = 0
        found = False

        PI = 3.14159265358979323846
        RAD2DEG = 180.0 / PI

        indx = mx.Sort(0, -1, 0)

        for i in range(nlines):
            freqs.append(-1 * mx.Fr(indx[i]) / (2.0 * PI * field))

        for i in range(nlines):
            freq = freqs[i]
            if (freq > ppmlo) and (freq < ppmhi):
                val = mx.I(indx[i])
                tmpa = np.sqrt(val.real()**2 + val.imag()**2) / qnscale
                tmpp = -RAD2DEG * np.angle(val.real() + 1j * val.imag())

            if nbin == 0:
                outf.append(freq)
                outa.append(tmpa)
                outp.append(tmpp)
                nbin += 1
            else:
                for k in range(nbin):
                    if (freq >= outf[k] - tolppm) and (freq <=
                                                       outf[k] + tolppm):
                        if (tmpp >= outp[k] - tolpha) and (tmpp <=
                                                           outp[k] + tolpha):
                            ampsum = outa[k] + tmpa
                            outf[k] = (outa[k] * outf[k] +
                                       tmpa * freq) / ampsum
                            outp[k] = (outa[k] * outp[k] +
                                       tmpa * tmpp) / ampsum
                            outa[k] += tmpa
                            found = True
                if not found:
                    outf.append(freq)
                    outa.append(tmpa)
                    outp.append(tmpp)
                    nbin += 1
                found = False

        for i, item in enumerate(outf):
            outf[i] = item + rf_off
            outp[i] = outp[i] - 90.0

        metab = Metabolite()
        metab.name = metab_name
        metab.var = 0.0

        for i in range(sp.size(outf)):
            if outf[i] <= 5:
                metab.ppm.append(outf[i])
                metab.area.append(outa[i])
                metab.phase.append(-1.0 * outp[i])

        insysfile = self.insysfile.replace('pints/metabolites/3T_', '')
        insysfile = self.insysfile.replace('pints/metabolites/7T_', '')
        insysfile = self.insysfile.replace('pints/metabolites/9.4T_', '')

        if insysfile == 'alanine.sys':  #
            metab.A_m = 0.078
            metab.T2 = (87E-3)
        elif insysfile == 'aspartate.sys':
            metab.A_m = 0.117
            metab.T2 = (87E-3)
        elif insysfile == 'choline_1-CH2_2-CH2.sys':  #
            metab.A_m = 0.165
            metab.T2 = (87E-3)
        elif insysfile == 'choline_N(CH3)3_a.sys' or insysfile == 'choline_N(CH3)3_b.sys':  #
            metab.A_m = 0.165
            metab.T2 = (121E-3)
        elif insysfile == 'creatine_N(CH3).sys':
            metab.A_m = 0.296
            metab.T2 = (90E-3)
        elif insysfile == 'creatine_X.sys':
            metab.A_m = 0.296
            metab.T2 = (81E-3)
        elif insysfile == 'd-glucose-alpha.sys':  #
            metab.A_m = 0.049
            metab.T2 = (87E-3)
        elif insysfile == 'd-glucose-beta.sys':  #
            metab.A_m = 0.049
            metab.T2 = (87E-3)
        elif insysfile == 'eth.sys':  #
            metab.A_m = 0.320
            metab.T2 = (87E-3)
        elif insysfile == 'gaba.sys':  #
            metab.A_m = 0.155
            metab.T2 = (82E-3)
        elif insysfile == 'glutamate.sys':
            metab.A_m = 0.898
            metab.T2 = (88E-3)
        elif insysfile == 'glutamine.sys':
            metab.A_m = 0.427
            metab.T2 = (87E-3)
        elif insysfile == 'glutathione_cysteine.sys':
            metab.A_m = 0.194
            metab.T2 = (87E-3)
        elif insysfile == 'glutathione_glutamate.sys':
            metab.A_m = 0.194
            metab.T2 = (87E-3)
        elif insysfile == 'glutathione_glycine.sys':
            metab.A_m = 0.194
            metab.T2 = (87E-3)
        elif insysfile == 'glycine.sys':
            metab.A_m = 0.068
            metab.T2 = (87E-3)
        elif insysfile == 'gpc_7-CH2_8-CH2.sys':  #
            metab.A_m = 0.097
            metab.T2 = (87E-3)
        elif insysfile == 'gpc_glycerol.sys':  #
            metab.A_m = 0.097
            metab.T2 = (87E-3)
        elif insysfile == 'gpc_N(CH3)3_a.sys':  #
            metab.A_m = 0.097
            metab.T2 = (121E-3)
        elif insysfile == 'gpc_N(CH3)3_b.sys':  #
            metab.A_m = 0.097
            metab.T2 = (121E-3)
        elif insysfile == 'lactate.sys':  #
            metab.A_m = 0.039
            metab.T2 = (87E-3)
        elif insysfile == 'myoinositol.sys':
            metab.A_m = 0.578
            metab.T2 = (87E-3)
        elif insysfile == 'naa_acetyl.sys':
            metab.A_m = 1.000
            metab.T2 = (130E-3)
        elif insysfile == 'naa_aspartate.sys':
            metab.A_m = 1.000
            metab.T2 = (69E-3)
        elif insysfile == 'naag_acetyl.sys':
            metab.A_m = 0.160
            metab.T2 = (130E-3)
        elif insysfile == 'naag_aspartyl.sys':
            metab.A_m = 0.160
            metab.T2 = (87E-3)
        elif insysfile == 'naag_glutamate.sys':
            metab.A_m = 0.160
            metab.T2 = (87E-3)
        elif insysfile == 'pcho_N(CH3)3_a.sys':  #
            metab.A_m = 0.058
            metab.T2 = (121E-3)
        elif insysfile == 'pcho_N(CH3)3_b.sys':  #
            metab.A_m = 0.058
            metab.T2 = (121E-3)
        elif insysfile == 'pcho_X.sys':  #
            metab.A_m = 0.058
            metab.T2 = (87E-3)
        elif insysfile == 'pcr_N(CH3).sys':
            metab.A_m = 0.422
            metab.T2 = (90E-3)
        elif insysfile == 'pcr_X.sys':
            metab.A_m = 0.422
            metab.T2 = (81E-3)
        elif insysfile == 'peth.sys':
            metab.A_m = 0.126
            metab.T2 = (87E-3)
        elif insysfile == 'scyllo-inositol.sys':
            metab.A_m = 0.044
            metab.T2 = (87E-3)
        elif insysfile == 'taurine.sys':
            metab.A_m = 0.117
            metab.T2 = (85E-3)
        elif insysfile == 'water.sys':
            metab.A_m = 1.000
            metab.T2 = (43.60E-3)

        # Send save data signal
        self.outputResults.emit(metab)
        self.postToConsole.emit('        | Simulation completed for ... ' +
                                self.insysfile)
        self.finished.emit(self.thread_num)
Ejemplo n.º 10
0
class SimpleMapWidget(BaseMapWidget):

    #tracks
    tracks_lat = np.array([])
    tracks_lon = np.array([])
    tracks_lat_pos = None
    tracks_lon_pos = None
    tracks_timestamp = None

    course_plot = None
    plot_verification = None
    course_points_plot = None
    course_point_text = None

    cuesheet_widget = None

    #misc
    y_mod = 1.22  #31/25 at Tokyo(N35)
    pre_zoomlevel = np.nan

    drawn_tile = {}
    tile_exists = {}
    map_cuesheet_ratio = 1  #map:cuesheet = 1:0

    font = ""

    #signal for physical button
    signal_search_route = QtCore.pyqtSignal()

    def setup_ui_extra(self):
        super().setup_ui_extra()

        #self.plot.showGrid(x=True, y=True, alpha=1)
        self.track_plot = self.plot.plot(
            pen=pg.mkPen(color=(0, 128, 255), width=8))
        #self.track_plot = self.plot.plot(pen=pg.mkPen(color=(0,192,255,128), width=8))

        self.scale_plot = self.plot.plot(pen=pg.mkPen(color=(0, 0,
                                                             0), width=3))
        self.scale_text = pg.TextItem(
            text="",
            anchor=(0.5, 1),
            angle=0,
            border=(255, 255, 255, 255),
            fill=(255, 255, 255, 255),
            color=(0, 0, 0),
        )
        self.scale_text.setZValue(100)
        self.plot.addItem(self.scale_text)

        self.map_attribution = pg.TextItem(
            #text = self.config.G_MAP_CONFIG[self.config.G_MAP]['attribution'],
            html=
            '<div style="text-align: right;"><span style="color: #000; font-size: 10px;">'
            + self.config.G_MAP_CONFIG[self.config.G_MAP]['attribution'] +
            '</span></div>',
            anchor=(1, 1),
            angle=0,
            border=(255, 255, 255, 255),
            fill=(255, 255, 255, 255),
            color=(0, 0, 0),
        )
        self.map_attribution.setZValue(100)
        self.plot.addItem(self.map_attribution)

        #self.load_course()
        t = datetime.datetime.utcnow()
        self.get_track()  #heavy when resume
        print("\tpyqt_graph : get_track(init) : ",
              (datetime.datetime.utcnow() - t).total_seconds(), "sec")

    def add_extra(self):

        #map
        self.layout.addWidget(self.plot, 0, 0, 4, 3)
        #print("### self.plot.width ###", self.plot.width())

        if self.config.G_AVAILABLE_DISPLAY[self.config.G_DISPLAY]['touch']:
            #zoom
            self.layout.addWidget(self.button['zoomdown'], 0, 0)
            self.layout.addWidget(self.button['lock'], 1, 0)
            self.layout.addWidget(self.button['zoomup'], 2, 0)
            #arrow
            self.layout.addWidget(self.button['left'], 0, 2)
            self.layout.addWidget(self.button['up'], 1, 2)
            self.layout.addWidget(self.button['down'], 2, 2)
            self.layout.addWidget(self.button['right'], 3, 2)

            if self.config.G_HAVE_GOOGLE_DIRECTION_API_TOKEN:
                self.layout.addWidget(self.button['go'], 3, 0)
                self.button['go'].clicked.connect(self.search_route)

        #for expanding column
        self.layout.setColumnMinimumWidth(0, 40)
        self.layout.setColumnStretch(1, 1)
        self.layout.setColumnMinimumWidth(2, 40)

        #cue sheet
        self.init_cuesheet()

        #center point (displays while moving the map)
        self.center_point = pg.ScatterPlotItem(pxMode=True, symbol="+")
        self.center_point_data = {
            'pos': [np.nan, np.nan],
            'size': 15,
            'pen': {
                'color': (0, 0, 0),
                'width': 2
            },
        }
        self.center_point_location = []

        #connect signal
        self.signal_search_route.connect(self.search_route)

    def init_cuesheet(self):
        #if self.config.G_CUESHEET_DISPLAY_NUM > 0:
        if len(
                self.config.logger.course.point_name
        ) > 0 and self.config.G_CUESHEET_DISPLAY_NUM > 0 and self.config.G_COURSE_INDEXING:
            self.cuesheet_widget = CueSheetWidget(self, self.config)
            self.map_cuesheet_ratio = 0.7
            self.layout.addWidget(self.cuesheet_widget, 0, 4, 4, 5)

    def resizeEvent(self, event):
        if len(
                self.config.logger.course.point_name
        ) == 0 or self.config.G_CUESHEET_DISPLAY_NUM == 0 or not self.config.G_COURSE_INDEXING:
            self.map_cuesheet_ratio = 1.0
        #if self.config.G_CUESHEET_DISPLAY_NUM > 0:
        else:
            self.cuesheet_widget.setFixedWidth(
                int(self.width() * (1 - self.map_cuesheet_ratio)))
            self.cuesheet_widget.setFixedHeight(self.height())
        self.plot.setFixedWidth(int(self.width() * (self.map_cuesheet_ratio)))
        self.plot.setFixedHeight(self.height())

    #override for long press
    def switch_lock(self):
        if self.button['lock'].isDown():
            if self.button['lock']._state == 0:
                self.button['lock']._state = 1
            else:
                self.button_press_count['lock'] += 1
                #long press
                if self.button_press_count[
                        'lock'] == self.config.G_BUTTON_LONG_PRESS:
                    self.change_move()
        elif self.button['lock']._state == 1:
            self.button['lock']._state = 0
            self.button_press_count['lock'] = 0
        #short press
        else:
            super().switch_lock()

    def load_course(self):
        if len(self.config.logger.course.latitude) == 0:
            return

        t = datetime.datetime.utcnow()

        if self.course_plot != None:
            self.plot.removeItem(self.course_plot)
        self.course_plot = pg.CoursePlotItem(
            x=self.config.logger.course.longitude,
            y=self.get_mod_lat_np(self.config.logger.course.latitude),
            brushes=self.config.logger.course.colored_altitude,
            width=6)
        self.plot.addItem(self.course_plot)

        #test
        if not self.config.G_IS_RASPI:
            if self.plot_verification != None:
                self.plot.removeItem(self.plot_verification)
            self.plot_verification = pg.ScatterPlotItem(pxMode=True)
            test_points = []
            for i in range(len(self.config.logger.course.longitude)):
                p = {
                    'pos': [
                        self.config.logger.course.longitude[i],
                        self.get_mod_lat(self.config.logger.course.latitude[i])
                    ],
                    'size':
                    2,
                    'pen': {
                        'color': 'w',
                        'width': 1
                    },
                    'brush':
                    pg.mkBrush(color=(255, 0, 0))
                }
                test_points.append(p)
            self.plot_verification.setData(test_points)
            self.plot.addItem(self.plot_verification)
        print("\tpyqt_graph : course plot : ",
              (datetime.datetime.utcnow() - t).total_seconds(), "sec")

        #course point
        if len(self.config.logger.course.point_longitude) == 0:
            return

        t = datetime.datetime.utcnow()

        if self.course_points_plot != None:
            self.plot.removeItem(self.course_points_plot)
        self.course_points_plot = pg.ScatterPlotItem(pxMode=True, symbol="t")
        self.course_points = []

        for i in reversed(range(len(
                self.config.logger.course.point_longitude))):
            #if self.config.logger.course.point_type[i] == "Straight":
            #  continue
            cp = {
                'pos': [
                    self.config.logger.course.point_longitude[i],
                    self.get_mod_lat(
                        self.config.logger.course.point_latitude[i])
                ],
                'size':
                10,
                'pen': {
                    'color': 'r',
                    'width': 1
                },
                'brush':
                pg.mkBrush(color=(255, 0, 0))
            }
            self.course_points.append(cp)
        self.course_points_plot.setData(self.course_points)
        self.plot.addItem(self.course_points_plot)

        print("\tpyqt_graph : load course points plot : ",
              (datetime.datetime.utcnow() - t).total_seconds(), "sec")

    def update_extra(self):

        #t = datetime.datetime.utcnow()

        #display current position
        if len(self.location) > 0:
            self.plot.removeItem(self.current_point)
            self.location.pop()
        #display center point
        if len(self.center_point_location) > 0:
            self.plot.removeItem(self.center_point)
            self.center_point_location.pop()

        #current position
        self.point['pos'] = [self.gps_values['lon'], self.gps_values['lat']]
        #dummy position
        if np.isnan(self.gps_values['lon']) and np.isnan(
                self.gps_values['lat']):
            #recent point(from log or pre_point) / course start / fix(TOKYO station)
            if len(self.tracks_lon) > 0 and len(self.tracks_lat) > 0:
                self.point['pos'] = [self.tracks_lon_pos, self.tracks_lat_pos]
            elif len(self.config.logger.course.longitude) > 0 and len(
                    self.config.logger.course.latitude) > 0:
                self.point['pos'] = [
                    self.config.logger.course.longitude[0],
                    self.config.logger.course.latitude[0]
                ]
            else:
                self.point['pos'] = [
                    self.config.G_DUMMY_POS_X, self.config.G_DUMMY_POS_Y
                ]
        #update y_mod (adjust for lat:lon=1:1)
        self.y_mod = self.calc_y_mod(self.point['pos'][1])
        #add position circle to map
        if not np.isnan(self.point['pos'][0]) and not np.isnan(
                self.point['pos'][1]):
            if self.gps_values['mode'] == 3:
                self.point['brush'] = self.point_color['fix']
            else:
                self.point['brush'] = self.point_color['lost']
        else:
            #set dummy
            self.point['brush'] = self.point_color['lost']

        #experimental
        #print("#### {:.2f}".format(self.get_altitude_from_tile(self.point['pos'])))

        #center position
        if self.lock_status:
            self.map_pos['x'] = self.point['pos'][0]
            self.map_pos['y'] = self.point['pos'][1]

        #set width and height
        self.map_area['w'], self.map_area['h'] = self.get_geo_area(
            self.map_pos['x'], self.map_pos['y'])

        #move
        x_move = y_move = 0
        if self.lock_status and len(
                self.config.logger.course.distance
        ) > 0 and self.gps_values['on_course_status']:
            index = self.gps_sensor.get_index_with_distance_cutoff(
                self.gps_values['course_index'],
                #get some distance [m]
                self.get_width_distance(self.map_pos['y'], self.map_area['w'])
                / 1000,
            )
            x2 = self.config.logger.course.longitude[index]
            y2 = self.config.logger.course.latitude[index]
            x_delta = x2 - self.map_pos['x']
            y_delta = y2 - self.map_pos['y']
            #slide from center
            x_move = 0.25 * self.map_area['w']
            y_move = 0.25 * self.map_area['h']
            if x_delta > x_move:
                self.map_pos['x'] += x_move
            elif x_delta < -x_move:
                self.map_pos['x'] -= x_move
            if y_delta > y_move:
                self.map_pos['y'] += y_move
            elif y_delta < -y_move:
                self.map_pos['y'] -= y_move
        elif not self.lock_status:
            if self.move_pos['x'] > 0:
                x_move = self.map_area['w'] / 2
            elif self.move_pos['x'] < 0:
                x_move = -self.map_area['w'] / 2
            if self.move_pos['y'] > 0:
                y_move = self.map_area['h'] / 2
            elif self.move_pos['y'] < 0:
                y_move = -self.map_area['h'] / 2
            self.map_pos['x'] += x_move / self.move_factor
            self.map_pos['y'] += y_move / self.move_factor
        self.move_pos['x'] = self.move_pos['y'] = 0

        self.map_area['w'], self.map_area['h'] = self.get_geo_area(
            self.map_pos['x'], self.map_pos['y'])

        #experimental
        #print("#### {:.2f}".format(self.get_altitude_from_tile([self.map_pos['x'], self.map_pos['y']])))

        ###########
        # drawing #
        ###########

        #current point
        #print(self.point['pos'])
        self.point['pos'][1] *= self.y_mod
        self.location.append(self.point)
        self.current_point.setData(self.location)
        self.plot.addItem(self.current_point)

        #center point
        if not self.lock_status:
            if self.move_adjust_mode:
                #self.center_point.setSymbol("d")
                self.center_point_data['size'] = 7.5
            else:
                #self.center_point.setSymbol("+")
                self.center_point_data['size'] = 15
            self.center_point_data['pos'][0] = self.map_pos['x']
            self.center_point_data['pos'][1] = self.get_mod_lat(
                self.map_pos['y'])
            self.center_point_location.append(self.center_point_data)
            self.center_point.setData(self.center_point_location)
            self.plot.addItem(self.center_point)

        #print("\tpyqt_graph : update_extra init : ", (datetime.datetime.utcnow()-t).total_seconds(), "sec")
        #t = datetime.datetime.utcnow()

        #set x and y ranges
        x_start = x_end = y_start = y_end = np.nan
        x_start = self.map_pos['x'] - self.map_area['w'] / 2
        x_end = x_start + self.map_area['w']
        y_start = self.map_pos['y'] - self.map_area['h'] / 2
        y_end = y_start + self.map_area['h']
        if not np.isnan(x_start) and not np.isnan(x_end):
            self.plot.setXRange(x_start, x_end, padding=0)
        if not np.isnan(y_start) and not np.isnan(y_end):
            self.plot.setYRange(self.get_mod_lat(y_start),
                                self.get_mod_lat(y_end),
                                padding=0)

        self.draw_map_tile(self.zoomlevel, x_start, x_end, y_start, y_end)
        #print("\tpyqt_graph : update_extra map : ", (datetime.datetime.utcnow()-t).total_seconds(), "sec")
        #t = datetime.datetime.utcnow()

        if not self.course_loaded:
            self.load_course()
            self.course_loaded = True

        #course_points and cuesheet
        self.draw_cuesheet()
        #print("\tpyqt_graph : update_extra cuesheet : ", (datetime.datetime.utcnow()-t).total_seconds(), "sec")
        #t = datetime.datetime.utcnow()

        #draw track
        self.get_track()
        self.track_plot.setData(self.tracks_lon, self.tracks_lat)
        #print("\tpyqt_graph : update_extra track : ", (datetime.datetime.utcnow()-t).total_seconds(), "sec")
        #t = datetime.datetime.utcnow()

        #draw scale
        self.draw_scale(x_start, y_start)
        #draw map attribution
        self.draw_map_attribution(x_start, y_start)
        #print("\tpyqt_graph : update_extra draw map : ", (datetime.datetime.utcnow()-t).total_seconds(), "sec")
        #t = datetime.datetime.utcnow()

    def get_track(self):
        #get track from SQL
        lon = []
        lat = []
        #not good (input & output)    #conversion coordinate
        (self.tracks_timestamp, lon, lat) = \
          self.config.logger.update_track(self.tracks_timestamp)
        if len(lon) > 0 and len(lat) > 0:
            self.tracks_lon_pos = lon[-1]
            self.tracks_lat_pos = lat[-1]
            self.tracks_lon = np.append(self.tracks_lon, np.array(lon))
            self.tracks_lat = np.append(self.tracks_lat,
                                        self.get_mod_lat_np(np.array(lat)))

    def reset_track(self):
        self.tracks_lon = []
        self.tracks_lat = []

    def search_route(self):
        if self.lock_status:
            return

        self.config.logger.course.search_route(
            self.point['pos'][0],
            self.point['pos'][1] / self.y_mod,
            self.map_pos['x'],
            self.map_pos['y'],
        )
        self.init_cuesheet()
        self.course_loaded = False
        self.resizeEvent(None)

    def draw_map_tile(self, pixel_z, x_start, x_end, y_start, y_end):

        #get tile coordinates of display border points
        p0 = {"x": min(x_start, x_end), "y": min(y_start, y_end)}
        p1 = {"x": max(x_start, x_end), "y": max(y_start, y_end)}
        #tile range
        t0 = self.get_tilexy_and_xy_in_tile(pixel_z, p0["x"], p0["y"])
        t1 = self.get_tilexy_and_xy_in_tile(pixel_z, p1["x"], p1["y"])
        tile_x = sorted([t0[0], t1[0]])
        tile_y = sorted([t0[1], t1[1]])

        #tile download check
        if self.zoomlevel not in self.tile_exists:
            self.tile_exists[self.zoomlevel] = {}

        tiles = []

        for i in range(tile_x[0], tile_x[1] + 1):
            for j in range(tile_y[0], tile_y[1] + 1):
                tiles.append((i, j))

        for i in [tile_x[0] - 1, tile_x[1] + 1]:
            for j in range(tile_y[0] - 1, tile_y[1] + 2):
                tiles.append((i, j))

        for i in range(tile_x[0], tile_x[1] + 1):
            for j in [tile_y[0] - 1, tile_y[1] + 1]:
                tiles.append((i, j))

        for tile in tiles:
            i = tile[0]
            j = tile[1]
            filename = self.config.get_maptile_filename(
                self.config.G_MAP, pixel_z, i, j)
            key = "{0}-{1}".format(i, j)

            if os.path.exists(filename) and os.path.getsize(filename) > 0:
                self.tile_exists[self.zoomlevel][key] = True
                continue

            #download is in progress
            if key in self.tile_exists[self.zoomlevel]:
                continue

            #start downloading
            self.tile_exists[self.zoomlevel][key] = False
            if not self.config.download_maptile(pixel_z, i, j):
                if self.tile_exists[self.zoomlevel] == None:
                    self.tile_exists[self.zoomlevel].discard(key)

        draw_flag = False
        if self.zoomlevel not in self.drawn_tile:
            self.drawn_tile[self.zoomlevel] = set()
            draw_flag = True
        if self.pre_zoomlevel != self.zoomlevel:
            self.drawn_tile[self.zoomlevel] = set()
            draw_flag = True
        for i in range(tile_x[0], tile_x[1] + 1):
            for j in range(tile_y[0], tile_y[1] + 1):
                key = "{0}-{1}".format(i, j)
                if self.tile_exists[self.zoomlevel][
                        key] and key not in self.drawn_tile[self.zoomlevel]:
                    self.drawn_tile[self.zoomlevel].add(key)
                    draw_flag = True
        self.pre_zoomlevel = self.zoomlevel

        if not draw_flag:
            return

        imgarray = np.empty(((tile_x[1] - tile_x[0] + 1) * 256,
                             (tile_y[1] - tile_y[0] + 1) * 256, 3),
                            dtype='uint8')
        for i in range(tile_x[0], tile_x[1] + 1):
            for j in range(tile_y[0], tile_y[1] + 1):
                filename = self.config.get_maptile_filename(
                    self.config.G_MAP, pixel_z, i, j)
                I = i - tile_x[0]
                J = tile_y[1] - j
                if os.path.exists(filename) and os.path.getsize(filename) > 0:
                    imgarray[I*256:(I+1)*256, J*256:(J+1)*256] = \
                      np.rot90(np.asarray(Image.open(filename).convert('RGB')).astype('uint8'), -1)
                else:
                    #finally blank area
                    imgarray[I * 256:(I + 1) * 256,
                             J * 256:(J + 1) * 256] = 255
        imgitem = pg.ImageItem(imgarray)
        saveimg = pg.ImageItem(np.fliplr(imgarray))
        #saveimg.save("maptile/out.png")

        imgarray_min_x, imgarray_max_y = \
          self.get_lon_lat_from_tile_xy(pixel_z, tile_x[0], tile_y[0])
        imgarray_max_x, imgarray_min_y = \
          self.get_lon_lat_from_tile_xy(pixel_z, tile_x[1]+1, tile_y[1]+1)

        self.plot.addItem(imgitem)
        imgitem.setZValue(-100)
        imgitem.setRect(
            pg.QtCore.QRectF(
                imgarray_min_x,
                self.get_mod_lat(imgarray_min_y),
                imgarray_max_x - imgarray_min_x,
                self.get_mod_lat(imgarray_max_y) -
                self.get_mod_lat(imgarray_min_y),
            ))
        x = imgarray_min_x
        y = self.get_mod_lat(imgarray_min_y)
        w = imgarray_max_x - imgarray_min_x
        h = self.get_mod_lat(imgarray_max_y) - self.get_mod_lat(imgarray_min_y)

    def draw_scale(self, x_start, y_start):
        #draw scale at left bottom
        scale_factor = 8
        scale_dist = self.get_width_distance(y_start,
                                             self.map_area['w']) / scale_factor
        num = scale_dist / (10**int(np.log10(scale_dist)))
        modify = 1
        if 1 < num < 2:
            modify = 2 / num
        elif 2 < num < 5:
            modify = 5 / num
        elif 5 < num < 10:
            modify = 10 / num
        scale_x1 = x_start + self.map_area['w'] / 25
        scale_x2 = scale_x1 + self.map_area['w'] / scale_factor * modify
        scale_y1 = y_start + self.map_area['h'] / 25
        scale_y2 = scale_y1 + self.map_area['h'] / 30
        scale_y1 = self.get_mod_lat(scale_y1)
        scale_y2 = self.get_mod_lat(scale_y2)
        self.scale_plot.setData(
            [scale_x1, scale_x1, scale_x2, scale_x2],
            [scale_y2, scale_y1, scale_y1, scale_y2],
        )

        scale_unit = "m"
        scale_label = round(scale_dist * modify)
        if scale_label >= 1000:
            scale_label = int(scale_label / 1000)
            scale_unit = "km"
        self.scale_text.setPlainText("{0}{1}".format(scale_label, scale_unit))
        self.scale_text.setPos((scale_x1 + scale_x2) / 2, scale_y2)

    def get_altitude_from_tile(self, pos):
        f_x, f_y, p_x, p_y = self.get_tilexy_and_xy_in_tile(
            self.zoomlevel, pos[0], pos[1])
        filename = self.config.get_maptile_filename(self.config.G_DEM_MAP,
                                                    self.zoomlevel, f_x, f_y)

        if not os.path.exists(filename) or os.path.getsize(filename) == 0:
            return np.nan

        imgarray = np.asarray(Image.open(filename))
        rgb_pos = imgarray[p_x, p_y]
        altitude = rgb_pos[0] * (2**16) + rgb_pos[1] * (2**8) + rgb_pos[2]
        if altitude < 2**23:
            altitude = altitude * 0.01
        elif altitude == 2**23:
            altitude = np.nan
        else:
            altitude = (altitude - 2**24) * 0.01

        #print("###altiude", altitude, rgb_pos)
        return altitude

    def draw_map_attribution(self, x_start, y_start):
        #draw map attribution at right bottom
        self.map_attribution.setPos(x_start + self.map_area['w'],
                                    self.get_mod_lat(y_start))

    def draw_cuesheet(self):
        if self.cuesheet_widget != None:
            self.cuesheet_widget.update_extra()

    def calc_y_mod(self, lat):
        if np.isnan(lat):
            return np.nan
        return self.config.GEO_R2 / (self.config.GEO_R1 *
                                     math.cos(lat / 180 * np.pi))

    def get_width_distance(self, lat, w):
        return w * self.config.GEO_R1 * 1000 * 2 * np.pi * math.cos(
            lat / 180 * np.pi) / 360

    def get_mod_lat(self, lat):
        return lat * self.calc_y_mod(lat)

    def get_mod_lat_np(self, lat):
        return lat * self.config.GEO_R2 / (self.config.GEO_R1 *
                                           np.cos(lat / 180 * np.pi))

    def get_geo_area(self, x, y):
        tile_x, tile_y, _, _ = self.get_tilexy_and_xy_in_tile(
            self.zoomlevel, x, y)
        pos_x0, pos_y0 = self.get_lon_lat_from_tile_xy(self.zoomlevel, tile_x,
                                                       tile_y)
        pos_x1, pos_y1 = self.get_lon_lat_from_tile_xy(self.zoomlevel,
                                                       tile_x + 1, tile_y + 1)
        return abs(pos_x1 - pos_x0) / 256 * (
            self.width() * self.map_cuesheet_ratio
        ), abs(pos_y1 - pos_y0) / 256 * self.height()

    def get_tilexy_and_xy_in_tile(self, z, x, y):
        n = 2.0**z
        _y = math.radians(y)
        x_in_tile, tile_x = math.modf((x + 180.0) / 360.0 * n)
        y_in_tile, tile_y = math.modf(
            (1.0 - math.log(math.tan(_y) +
                            (1.0 / math.cos(_y))) / math.pi) / 2.0 * n)

        return int(tile_x), int(tile_y), int(x_in_tile * 256), int(y_in_tile *
                                                                   256)

    def get_lon_lat_from_tile_xy(self, z, x, y):
        n = 2.0**z
        lon = x / n * 360.0 - 180.0
        lat = math.degrees(math.atan(math.sinh(math.pi * (1 - 2 * y / n))))

        return lon, lat
Ejemplo n.º 11
0
class PointWidget(QtWidgets.QWidget, WIDGET):
    hide_custom_fields = QtCore.pyqtSignal(bool)
    saving = QtCore.pyqtSignal()

    def __init__(self, canvas, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        self.setupUi(self)
        self.canvas = canvas

        self.pushButtonAddClass.clicked.connect(self.add_class)
        self.pushButtonRemoveClass.clicked.connect(self.remove_class)
        self.pushButtonImport.clicked.connect(self.import_metadata)
        self.pushButtonSave.clicked.connect(self.save)
        self.pushButtonLoadPoints.clicked.connect(self.load)
        self.pushButtonReset.clicked.connect(self.reset)
        self.pushButtonExport.clicked.connect(self.export)

        self.pushButtonExport.setIcon(QtGui.QIcon('icons:export.svg'))
        self.pushButtonReset.setIcon(QtGui.QIcon('icons:reset.svg'))
        self.pushButtonImport.setIcon(QtGui.QIcon('icons:import.svg'))
        self.pushButtonSave.setIcon(QtGui.QIcon('icons:save.svg'))
        self.pushButtonLoadPoints.setIcon(QtGui.QIcon('icons:load.svg'))
        self.pushButtonRemoveClass.setIcon(QtGui.QIcon('icons:delete.svg'))
        self.pushButtonAddClass.setIcon(QtGui.QIcon('icons:add.svg'))

        self.tableWidgetClasses.verticalHeader().setVisible(False)
        self.tableWidgetClasses.horizontalHeader().setMinimumSectionSize(1)
        self.tableWidgetClasses.horizontalHeader().setStretchLastSection(False)
        self.tableWidgetClasses.horizontalHeader().setSectionResizeMode(
            0, QtWidgets.QHeaderView.ResizeMode.Stretch)
        self.tableWidgetClasses.setColumnWidth(1, 30)
        self.tableWidgetClasses.cellClicked.connect(self.cell_clicked)
        self.tableWidgetClasses.cellChanged.connect(self.cell_changed)
        self.tableWidgetClasses.selectionModel().selectionChanged.connect(
            self.selection_changed)

        self.checkBoxDisplayPoints.toggled.connect(self.display_points)
        self.checkBoxDisplayGrid.toggled.connect(self.display_grid)
        self.canvas.image_loaded.connect(self.image_loaded)
        self.canvas.update_point_count.connect(self.update_point_count)
        self.canvas.points_loaded.connect(self.points_loaded)
        self.canvas.metadata_imported.connect(self.display_count_tree)

        self.model = QtGui.QStandardItemModel()
        self.current_model_index = QtCore.QModelIndex()
        self.treeView.setModel(self.model)
        self.reset_model()
        self.treeView.doubleClicked.connect(self.select_model_item)

        self.previous_file_name = None  # used for quick save

        self.spinBoxPointRadius.valueChanged.connect(
            self.canvas.set_point_radius)
        self.spinBoxGrid.valueChanged.connect(self.canvas.set_grid_size)

        icon = QtGui.QPixmap(20, 20)
        icon.fill(QtCore.Qt.GlobalColor.yellow)
        self.labelPointColor.setPixmap(icon)
        self.labelPointColor.mousePressEvent = self.change_active_point_color
        icon = QtGui.QPixmap(20, 20)
        icon.fill(QtCore.Qt.GlobalColor.white)
        self.labelGridColor.setPixmap(icon)
        self.labelGridColor.mousePressEvent = self.change_grid_color

        self.checkBoxImageFields.clicked.connect(self.hide_custom_fields.emit)

    def add_class(self):
        class_name, ok = QtWidgets.QInputDialog.getText(
            self, 'New Class', 'Class Name')
        if ok:
            self.canvas.add_class(class_name)
            self.display_classes()
            self.display_count_tree()

    def display_grid(self, display):
        self.canvas.toggle_grid(display=display)

    def display_points(self, display):
        self.canvas.toggle_points(display=display)

    def cell_changed(self, row, column):
        if column == 0:
            old_class = self.canvas.classes[row]
            new_class = self.tableWidgetClasses.item(row, column).text()
            if old_class != new_class:
                self.tableWidgetClasses.selectionModel().clear()
                self.canvas.rename_class(old_class, new_class)
                self.display_classes()
                self.display_count_tree()

    def cell_clicked(self, row, column):
        if column == 1:
            color = QtWidgets.QColorDialog.getColor()
            if color.isValid():
                self.canvas.colors[self.canvas.classes[row]] = color
                item = QtWidgets.QTableWidgetItem()
                icon = QtGui.QPixmap(20, 20)
                icon.fill(color)
                item.setData(QtCore.Qt.ItemDataRole.DecorationRole, icon)
                self.tableWidgetClasses.setItem(row, 1, item)

    def change_active_point_color(self, event):
        color = QtWidgets.QColorDialog.getColor()
        if color.isValid():
            self.set_active_point_color(color)

    def change_grid_color(self, event):
        color = QtWidgets.QColorDialog.getColor()
        if color.isValid():
            self.set_grid_color(color)

    def display_classes(self):
        self.tableWidgetClasses.setRowCount(len(self.canvas.classes))
        row = 0
        for class_name in self.canvas.classes:
            item = QtWidgets.QTableWidgetItem(class_name)
            self.tableWidgetClasses.setItem(row, 0, item)

            item = QtWidgets.QTableWidgetItem()
            icon = QtGui.QPixmap(20, 20)
            icon.fill(self.canvas.colors[class_name])
            item.setData(QtCore.Qt.ItemDataRole.DecorationRole, icon)
            self.tableWidgetClasses.setItem(row, 1, item)
            row += 1
        self.tableWidgetClasses.selectionModel().clear()

    def display_count_tree(self):
        self.reset_model()
        for image in self.canvas.points:
            image_item = QtGui.QStandardItem(image)
            image_item.setEditable(False)
            class_item = QtGui.QStandardItem('')
            class_item.setEditable(False)
            self.model.appendRow([image_item, class_item])
            if image == self.canvas.current_image_name:
                font = image_item.font()
                font.setBold(True)
                image_item.setFont(font)
                self.treeView.setExpanded(image_item.index(), True)
                self.current_model_index = image_item.index()

            for class_name in self.canvas.classes:
                class_item = QtGui.QStandardItem(class_name)
                class_item.setEditable(False)
                class_item.setSelectable(False)
                class_count = QtGui.QStandardItem('0')
                if class_name in self.canvas.points[image]:
                    class_count = QtGui.QStandardItem(
                        str(len(self.canvas.points[image][class_name])))
                class_count.setEditable(False)
                class_count.setSelectable(False)
                image_item.appendRow([class_item, class_count])
        self.treeView.scrollTo(self.current_model_index)

    def export(self):
        if self.radioButtonCounts.isChecked():
            file_name = QtWidgets.QFileDialog.getSaveFileName(
                self, 'Export Count Summary',
                os.path.join(self.canvas.directory, 'counts.csv'),
                'Text CSV (*.csv)')
            if file_name[0] != '':
                self.canvas.export_counts(file_name[0],
                                          self.lineEditSurveyId.text())
        elif self.radioButtonPoints.isChecked():
            file_name = QtWidgets.QFileDialog.getSaveFileName(
                self, 'Export Points',
                os.path.join(self.canvas.directory, 'points.csv'),
                'Text CSV (*.csv)')
            if file_name[0] != '':
                self.canvas.export_points(file_name[0],
                                          self.lineEditSurveyId.text())
        else:
            self.chip_dialog = ChipDialog(self.canvas.classes,
                                          self.canvas.points,
                                          self.canvas.directory,
                                          self.lineEditSurveyId.text())
            self.chip_dialog.show()

    def image_loaded(self, directory, file_name):
        # self.tableWidgetClasses.selectionModel().clear()
        self.display_count_tree()

    def import_metadata(self):
        file_name = QtWidgets.QFileDialog.getOpenFileName(
            self, 'Select Points File', self.canvas.directory,
            'Point Files (*.pnt)')
        if file_name[0] != '':
            self.canvas.import_metadata(file_name[0])

    def load(self):
        file_name = QtWidgets.QFileDialog.getOpenFileName(
            self, 'Select Points File', self.canvas.directory,
            'Point Files (*.pnt)')
        if file_name[0] != '':
            self.previous_file_name = file_name[0]
            self.canvas.load_points(file_name[0])

    def next(self):
        max_index = self.model.rowCount()
        next_index = self.current_model_index.row() + 1
        if next_index < max_index:
            item = self.model.item(next_index)
            self.select_model_item(item.index())

    def points_loaded(self, survey_id):
        self.lineEditSurveyId.setText(survey_id)
        self.display_classes()
        self.update_ui_settings()

    def previous(self):
        next_index = self.current_model_index.row() - 1
        if next_index >= 0:
            item = self.model.item(next_index)
            self.select_model_item(item.index())

    def reset(self):
        msgBox = QtWidgets.QMessageBox()
        msgBox.setWindowTitle('Warning')
        msgBox.setText('You are about to clear all data')
        msgBox.setInformativeText('Do you want to continue?')
        msgBox.setStandardButtons(QtWidgets.QMessageBox.StandardButton.Cancel
                                  | QtWidgets.QMessageBox.StandardButton.Ok)
        msgBox.setDefaultButton(QtWidgets.QMessageBox.StandardButton.Cancel)
        response = msgBox.exec()
        if response == QtWidgets.QMessageBox.StandardButton.Ok:
            self.canvas.reset()
            self.display_classes()
            self.display_count_tree()
            self.previous_file_name = None

    def reset_model(self):
        self.current_model_index = QtCore.QModelIndex()
        self.model.clear()
        self.model.setColumnCount(2)
        self.model.setHeaderData(0, QtCore.Qt.Orientation.Horizontal, 'Image')
        self.model.setHeaderData(1, QtCore.Qt.Orientation.Horizontal, 'Count')
        self.treeView.setExpandsOnDoubleClick(False)
        self.treeView.header().setStretchLastSection(False)
        self.treeView.header().setSectionResizeMode(
            0, QtWidgets.QHeaderView.ResizeMode.Stretch)
        self.treeView.setTextElideMode(QtCore.Qt.TextElideMode.ElideMiddle)

    def remove_class(self):
        indexes = self.tableWidgetClasses.selectedIndexes()
        if len(indexes) > 0:
            class_name = self.canvas.classes[indexes[0].row()]
            msgBox = QtWidgets.QMessageBox()
            msgBox.setWindowTitle('Warning')
            msgBox.setText(
                'You are about to remove class [{}] '.format(class_name))
            msgBox.setInformativeText('Do you want to continue?')
            msgBox.setStandardButtons(QtWidgets.QMessageBox.Cancel
                                      | QtWidgets.QMessageBox.Ok)
            msgBox.setDefaultButton(QtWidgets.QMessageBox.Cancel)
            response = msgBox.exec()
            if response == QtWidgets.QMessageBox.Ok:
                self.canvas.remove_class(class_name)
                self.display_classes()
                self.display_count_tree()

    def quick_save(self):
        if self.previous_file_name is None:
            self.save()
        else:
            self.saving.emit()
            self.canvas.save_points(self.previous_file_name,
                                    self.lineEditSurveyId.text())

    def save(self, override=False):
        file_name = QtWidgets.QFileDialog.getSaveFileName(
            self, 'Save Points',
            os.path.join(self.canvas.directory, 'untitled.pnt'),
            'Point Files (*.pnt)')
        if file_name[0] != '':
            self.previous_file_name = file_name[0]
            if override is False and self.canvas.directory != os.path.split(
                    file_name[0])[0]:
                QtWidgets.QMessageBox.warning(
                    self.parent(), 'ERROR',
                    'You are attempting to save the pnt file outside of the working directory. Operation canceled. POINT DATA NOT SAVED.',
                    QtWidgets.QMessageBox.Ok)
            else:
                if self.canvas.save_points(
                        file_name[0], self.lineEditSurveyId.text()) is False:
                    msg_box = QtWidgets.QMessageBox()
                    msg_box.setWindowTitle('ERROR')
                    msg_box.setText('Save Failed!')
                    msg_box.setInformativeText(
                        'It appears you cannot save your pnt file in the working directory, possibly due to permissions.\n\nEither change the permissions on the folder or click the SAVE button and select another location outside of the working directory. Remember to copy of the pnt file back into the current working directory. '
                    )
                    msg_box.setStandardButtons(QtWidgets.QMessageBox.Save
                                               | QtWidgets.QMessageBox.Cancel)
                    msg_box.setDefaultButton(QtWidgets.QMessageBox.Save)
                    response = msg_box.exec()
                    if response == QtWidgets.QMessageBox.Save:
                        self.save(True)

    def select_model_item(self, model_index):
        item = self.model.itemFromIndex(model_index)
        if item.isSelectable():
            if item.column() != 0:
                index = self.model.index(item.row(), 0)
                item = self.model.itemFromIndex(index)
            path = os.path.join(self.canvas.directory, item.text())
            self.canvas.load_image(path)

    def selection_changed(self, selected, deselected):
        if len(selected.indexes()) > 0:
            self.canvas.set_current_class(selected.indexes()[0].row())
        else:
            self.canvas.set_current_class(None)

    def set_active_point_color(self, color):
        icon = QtGui.QPixmap(20, 20)
        icon.fill(color)
        self.labelPointColor.setPixmap(icon)
        self.canvas.set_point_color(color)

    def set_active_class(self, row):
        if row < self.tableWidgetClasses.rowCount():
            self.tableWidgetClasses.selectRow(row)

    def set_grid_color(self, color):
        icon = QtGui.QPixmap(20, 20)
        icon.fill(color)
        self.labelGridColor.setPixmap(icon)
        self.canvas.set_grid_color(color)

    def update_point_count(self, image_name, class_name, class_count):
        items = self.model.findItems(image_name)
        if len(items) == 0:
            self.display_count_tree()
        else:
            items[0].child(self.canvas.classes.index(class_name),
                           1).setText(str(class_count))

    def update_ui_settings(self):
        ui = self.canvas.ui
        color = QtGui.QColor(ui['point']['color'][0], ui['point']['color'][1],
                             ui['point']['color'][2])
        self.set_active_point_color(color)
        self.spinBoxPointRadius.setValue(ui['point']['radius'])
        color = QtGui.QColor(ui['grid']['color'][0], ui['grid']['color'][1],
                             ui['grid']['color'][2])
        self.set_grid_color(color)
        self.spinBoxGrid.setValue(ui['grid']['size'])
Ejemplo n.º 12
0
class PanningWebView(QWidget):
    ZOOM_WHEEL = 0.2
    webViewScrolled = QtCore.pyqtSignal(bool)
    webViewResized = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        super(PanningWebView, self).__init__()
        self.zoom = 1.0
        self.wheel_dir = 1.0
        self.setImgSize(QtCore.QSize(100, 80))
        self.pressed = False
        self.scrolling = False
        self.positionMousePress = None
        self.scrollMousePress = None
        self.handIsClosed = False
        # self.setContextMenuPolicy(Qt.CustomContextMenu) todo fix this
        self.scrollPos = QPointF(0.0, 0.0)
        # self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True) todo fix this
        self.setMouseTracking(True)
        self.svgRenderer = QtSvg.QSvgRenderer()
        self.svgRenderer.setAspectRatioMode(
            Qt.AspectRatioMode.KeepAspectRatioByExpanding)
        self.svgRenderer.repaintNeeded.connect(self.update)

    def setContent(self, cnt, type):
        if self.scrolling:
            return False
        if not self.svgRenderer.load(cnt):
            logging.error("error during parse of svg data")
        self.setImgSize(self.svgRenderer.defaultSize())
        self.svgRenderer.setFramesPerSecond(0)
        self.svgRenderer.setAspectRatioMode(Qt.AspectRatioMode.KeepAspectRatio)
        return True

    def setImgSize(self, newsize: QtCore.QSize):
        self.imgSize = newsize

    def resizeEvent(self, event: QResizeEvent):
        self.webViewResized.emit()
        super().resizeEvent(event)

    def paintEvent(self, event):
        if self.svgRenderer:
            painter = QPainter(self)
            rect = QtCore.QRectF(
                -self.scrollPos.x(),
                -self.scrollPos.y(),
                self.svgRenderer.defaultSize().width() * self.zoom,
                self.svgRenderer.defaultSize().height() * self.zoom,
            )
            self.svgRenderer.render(painter, rect)

    def setZoomFactor(self, zoom):
        if zoom > 8:
            zoom = 8
        elif zoom < 0.5:
            zoom = 0.5
        if self.zoom != zoom:
            self.zoom = zoom
            self.webViewResized.emit()
            if self.imgSize.isValid():
                self.setImgSize(self.imgSize)
            self.update()

    def zoomFactor(self):
        return self.zoom

    def scrollPosition(self) -> QPointF:
        return self.scrollPos

    def setScrollPosition(self, pos: QPoint):
        if self.scrollPos != pos:
            self.scrollPos = pos
            self.webViewResized.emit()
        self.update()

    def zoomIn(self, pos=None):
        if pos == None:
            self.setZoomFactor(self.zoomFactor() * (1.0 + self.ZOOM_WHEEL))
        else:
            elemOri = self.mapPosFromPos(pos)
            self.setZoomFactor(self.zoom * (1.0 + self.ZOOM_WHEEL))
            elemDelta = elemOri - self.mapPosFromPos(pos)
            self.scrollPos = QPointF(self.scrollPos) + elemDelta * self.zoom

    def zoomOut(self, pos=None):
        if pos == None:
            self.setZoomFactor(self.zoom * (1.0 - self.ZOOM_WHEEL))
        else:
            elem_ori = self.mapPosFromPos(pos)
            self.setZoomFactor(self.zoom * (1.0 - self.ZOOM_WHEEL))
            elem_delta = elem_ori - self.mapPosFromPos(pos)
            self.scrollPos = QPointF(self.scrollPos) + elem_delta * self.zoom

    def wheelEvent(self, event: QWheelEvent):
        if (self.wheel_dir * event.angleDelta().y()) < 0:
            self.zoomIn(event.position())
        elif (self.wheel_dir * event.angleDelta().y()) > 0:
            self.zoomOut(event.position())

    def mousePressEvent(self, mouseEvent: QMouseEvent):
        if (not self.pressed and not self.scrolling and mouseEvent.modifiers()
                == QtCore.Qt.KeyboardModifier.NoModifier):
            if mouseEvent.buttons() == QtCore.Qt.MouseButton.LeftButton:
                self.pressed = True
                self.scrolling = False
                self.handIsClosed = False
                QApplication.setOverrideCursor(
                    QtCore.Qt.CursorShape.OpenHandCursor)
                self.scrollMousePress = self.scrollPosition()
                self.positionMousePress = mouseEvent.pos()

    def mouseReleaseEvent(self, mouseEvent: QMouseEvent):
        if self.scrolling:
            self.pressed = False
            self.scrolling = False
            self.handIsClosed = False
            self.positionMousePress = None
            QApplication.restoreOverrideCursor()
            self.webViewScrolled.emit(False)
            return

        if self.pressed:
            self.pressed = False
            self.scrolling = False
            self.handIsClosed = False
            QApplication.restoreOverrideCursor()
            return

    def hoveCheck(self, pos: QPointF) -> bool:
        return False

    def doubleClicked(self, pos: QPointF) -> bool:
        return False

    def mouseDoubleClickEvent(self, mouseEvent: QMouseEvent):
        self.doubleClicked(self.mapPosFromEvent(mouseEvent))

    def mapPosFromPos(self, pos: QPointF) -> QPointF:
        return (pos + QPointF(self.scrollPos)) / self.zoom

    def mapPosFromPoint(self, mouseEvent: QPoint) -> QPoint:
        return (mouseEvent + QPointF(self.scrollPos)) / self.zoom

    def mapPosFromEvent(self, mouseEvent: QMouseEvent) -> QPointF:
        return (QPointF(mouseEvent.pos()) +
                QPointF(self.scrollPos)) / self.zoom

    def mouseMoveEvent(self, mouseEvent: QMouseEvent):
        if self.scrolling:
            if not self.handIsClosed:
                QApplication.restoreOverrideCursor()
                QApplication.setOverrideCursor(
                    QtCore.Qt.CursorShape.OpenHandCursor)
                self.handIsClosed = True
            if self.scrollMousePress != None:
                delta = mouseEvent.pos() - self.positionMousePress
                self.setScrollPosition(
                    QPoint(int(self.scrollMousePress.x()),
                           int(self.scrollMousePress.y())) - delta)
            return
        if self.pressed:
            self.pressed = False
            self.scrolling = True
            self.webViewScrolled.emit(True)
            return
        if self.hoveCheck(self.mapPosFromEvent(mouseEvent)):
            QApplication.setOverrideCursor(
                QtCore.Qt.CursorShape.PointingHandCursor)
        else:
            QApplication.setOverrideCursor(QtCore.Qt.CursorShape.ArrowCursor)
        return
Ejemplo n.º 13
0
class Exporter(QtCore.QThread):
    progress = QtCore.pyqtSignal(int)

    def __init__(self, survey_id, classes, points, working_directory,
                 output_directory, width, height, file_type):
        QtCore.QThread.__init__(self)
        self.survey_id = survey_id
        self.classes = classes
        self.points = points
        self.working_directory = working_directory
        self.output_directory = output_directory
        self.x_offset = width // 2
        self.y_offset = height // 2
        self.file_type = file_type

        self.totals = {}
        for class_name in classes:
            self.totals[class_name] = 0

    def run(self):
        for class_name in self.classes:
            os.makedirs('{}{}{}'.format(self.output_directory, os.path.sep,
                                        class_name))
        summary_file_name = '{}{}summary.csv'.format(self.output_directory,
                                                     os.path.sep)
        summary_file = open(summary_file_name, 'w')
        output = 'survey id,image,class,x,y,chip name'
        summary_file.write(output)
        progress = 2
        for image in self.points:
            file = Image.open('{}{}{}'.format(self.working_directory,
                                              os.path.sep, image))
            img = np.array(file)
            file.close()
            for class_name in self.classes:
                if class_name in self.points[image]:
                    directory = '{}{}{}{}'.format(self.output_directory,
                                                  os.path.sep, class_name,
                                                  os.path.sep)
                    for point in self.points[image][class_name]:
                        progress += 1
                        # set up file name and summary entry
                        self.totals[class_name] += 1
                        file_name = '{:010d}{}'.format(self.totals[class_name],
                                                       self.file_type)
                        chip_name = '{}{}'.format(directory, file_name)
                        output = '\n{},{},{},{},{},{}'.format(
                            self.survey_id, image, class_name, point.x(),
                            point.y(), chip_name)
                        summary_file.write(output)
                        # caculate the clip window
                        x = max(0, int(point.x()) - self.x_offset)
                        y = max(0, int(point.y()) - self.y_offset)
                        x2 = min((int(point.x()) - self.x_offset) +
                                 (self.x_offset * 2), img.shape[1])
                        y2 = min((int(point.y()) - self.y_offset) +
                                 (self.y_offset * 2), img.shape[0])
                        window = img[y:y2, x:x2]
                        # fill the chip with data and save
                        chip = np.zeros((self.y_offset * 2, self.x_offset * 2,
                                         img.shape[2]), img.dtype)
                        chip[0:window.shape[0], 0:window.shape[1]] = window
                        out_image = Image.fromarray(chip)
                        out_image.save(chip_name)
                        out_image.close()

                        self.progress.emit(progress)
        summary_file.close()
Ejemplo n.º 14
0
class CentralWidget(QtWidgets.QDialog, CLASS_DIALOG):

    load_custom_data = QtCore.pyqtSignal(dict)

    def __init__(self, parent=None):
        QtWidgets.QDialog.__init__(self)
        self.setupUi(self)
        self.canvas = Canvas()

        self.point_widget = PointWidget(self.canvas, self)
        self.findChild(QtWidgets.QFrame,
                       'framePointWidget').layout().addWidget(
                           self.point_widget)
        self.point_widget.hide_custom_fields.connect(self.hide_custom_fields)
        self.point_widget.saving.connect(self.display_quick_save)

        # Set up keyboard shortcuts
        self.save_shortcut = QtGui.QShortcut(
            QtGui.QKeySequence(self.tr("Ctrl+S")),
            self)  # quick save using Ctrl+S
        self.save_shortcut.setContext(
            QtCore.Qt.ShortcutContext.WidgetWithChildrenShortcut)
        self.save_shortcut.activated.connect(self.point_widget.quick_save)

        self.up_arrow = QtGui.QShortcut(
            QtGui.QKeySequence(QtCore.Qt.Key.Key_Up), self)
        self.up_arrow.setContext(
            QtCore.Qt.ShortcutContext.WidgetWithChildrenShortcut)
        self.up_arrow.activated.connect(self.point_widget.previous)

        self.down_arrow = QtGui.QShortcut(
            QtGui.QKeySequence(QtCore.Qt.Key.Key_Down), self)
        self.down_arrow.setContext(
            QtCore.Qt.ShortcutContext.WidgetWithChildrenShortcut)
        self.down_arrow.activated.connect(self.point_widget.next)

        # same as arrows but conventient for right handed people
        self.up_arrow = QtGui.QShortcut(QtGui.QKeySequence(self.tr("W")), self)
        self.up_arrow.setContext(
            QtCore.Qt.ShortcutContext.WidgetWithChildrenShortcut)
        self.up_arrow.activated.connect(self.point_widget.previous)

        self.down_arrow = QtGui.QShortcut(QtGui.QKeySequence(self.tr("S")),
                                          self)
        self.down_arrow.setContext(
            QtCore.Qt.ShortcutContext.WidgetWithChildrenShortcut)
        self.down_arrow.activated.connect(self.point_widget.next)

        # Make signal slot connections
        self.graphicsView.setScene(self.canvas)
        self.graphicsView.drop_complete.connect(self.canvas.load)
        self.graphicsView.region_selected.connect(self.canvas.select_points)
        self.graphicsView.delete_selection.connect(
            self.canvas.delete_selected_points)
        self.graphicsView.relabel_selection.connect(
            self.canvas.relabel_selected_points)
        self.graphicsView.toggle_points.connect(
            self.point_widget.checkBoxDisplayPoints.toggle)
        self.graphicsView.toggle_grid.connect(
            self.point_widget.checkBoxDisplayGrid.toggle)
        self.graphicsView.switch_class.connect(
            self.point_widget.set_active_class)
        self.graphicsView.add_point.connect(self.canvas.add_point)
        self.canvas.image_loaded.connect(self.graphicsView.image_loaded)
        self.canvas.directory_set.connect(self.display_working_directory)

        # Image data fields
        self.canvas.image_loaded.connect(self.display_coordinates)
        self.canvas.image_loaded.connect(self.get_custom_field_data)
        self.canvas.fields_updated.connect(self.display_custom_fields)
        self.lineEditX.textEdited.connect(self.update_coordinates)
        self.lineEditY.textEdited.connect(self.update_coordinates)

        # Buttons
        self.pushButtonAddField.clicked.connect(self.add_field_dialog)
        self.pushButtonDeleteField.clicked.connect(self.delete_field_dialog)
        self.pushButtonFolder.clicked.connect(self.select_folder)
        self.pushButtonZoomOut.clicked.connect(self.graphicsView.zoom_out)
        self.pushButtonZoomIn.clicked.connect(self.graphicsView.zoom_in)

        # Fix icons since no QRC file integration
        self.pushButtonFolder.setIcon(QtGui.QIcon('icons:folder.svg'))
        self.pushButtonZoomIn.setIcon(QtGui.QIcon('icons:zoom_in.svg'))
        self.pushButtonZoomOut.setIcon(QtGui.QIcon('icons:zoom_out.svg'))
        self.pushButtonDeleteField.setIcon(QtGui.QIcon('icons:delete.svg'))
        self.pushButtonAddField.setIcon(QtGui.QIcon('icons:add.svg'))

        self.quick_save_frame = QtWidgets.QFrame(self.graphicsView)
        self.quick_save_frame.setStyleSheet(
            "QFrame { background: #4caf50;color: #FFF;font-weight: bold}")
        self.quick_save_frame.setLayout(QtWidgets.QHBoxLayout())
        self.quick_save_frame.layout().addWidget(QtWidgets.QLabel('Saving...'))
        self.quick_save_frame.setGeometry(3, 3, 100, 35)
        self.quick_save_frame.hide()

    def resizeEvent(self, theEvent):
        self.graphicsView.resize_image()

    # Image data field functions
    def add_field(self):
        field_def = (self.field_name.text(), self.field_type.currentText())
        field_names = [x[0] for x in self.canvas.custom_fields['fields']]
        if field_def[0] in field_names:
            QtWidgets.QMessageBox.warning(self, 'Warning',
                                          'Field name already exists')
        else:
            self.canvas.add_custom_field(field_def)
            self.add_dialog.close()

    def add_field_dialog(self):
        self.field_name = QtWidgets.QLineEdit()
        self.field_type = QtWidgets.QComboBox()
        self.field_type.addItems(['line', 'box'])
        self.add_button = QtWidgets.QPushButton('Save')
        self.add_button.clicked.connect(self.add_field)
        self.add_dialog = QtWidgets.QDialog(self)
        self.add_dialog.setWindowTitle('Add Custom Field')
        self.add_dialog.setLayout(QtWidgets.QVBoxLayout())
        self.add_dialog.layout().addWidget(self.field_name)
        self.add_dialog.layout().addWidget(self.field_type)
        self.add_dialog.layout().addWidget(self.add_button)
        self.add_dialog.resize(250, self.add_dialog.height())
        self.add_dialog.show()

    def delete_field(self):
        self.canvas.delete_custom_field(self.field_list.currentText())
        self.delete_dialog.close()

    def delete_field_dialog(self):
        self.field_list = QtWidgets.QComboBox()
        self.field_list.addItems(
            [x[0] for x in self.canvas.custom_fields['fields']])
        self.delete_button = QtWidgets.QPushButton('Delete')
        self.delete_button.clicked.connect(self.delete_field)
        self.delete_dialog = QtWidgets.QDialog(self)
        self.delete_dialog.setWindowTitle('Delete Custom Field')
        self.delete_dialog.setLayout(QtWidgets.QVBoxLayout())
        self.delete_dialog.layout().addWidget(self.field_list)
        self.delete_dialog.layout().addWidget(self.delete_button)
        self.delete_dialog.resize(250, self.delete_dialog.height())
        self.delete_dialog.show()

    def display_coordinates(self, directory, image):
        if image in self.canvas.coordinates:
            self.lineEditX.setText(self.canvas.coordinates[image]['x'])
            self.lineEditY.setText(self.canvas.coordinates[image]['y'])
        else:
            self.lineEditX.setText('')
            self.lineEditY.setText('')

    def display_custom_fields(self, fields):
        def build(item):
            container = QtWidgets.QGroupBox(item[0], self)
            container.setObjectName(item[0])
            container.setLayout(QtWidgets.QVBoxLayout())
            if item[1].lower() == 'line':
                edit = LineText(container)
            else:
                edit = BoxText(container)
            edit.update.connect(self.canvas.save_custom_field_data)
            self.load_custom_data.connect(edit.load_data)
            container.layout().addWidget(edit)
            return container

        custom_fields = self.findChild(QtWidgets.QFrame, 'frameCustomFields')
        if custom_fields.layout() is None:
            custom_fields.setLayout(QtWidgets.QVBoxLayout())
        else:
            layout = custom_fields.layout()
            while layout.count():
                child = layout.takeAt(0)
                if child.widget():
                    child.widget().deleteLater()

        for item in fields:
            widget = build(item)
            custom_fields.layout().addWidget(widget)
        v = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum,
                                  QtWidgets.QSizePolicy.Policy.Expanding)
        custom_fields.layout().addItem(v)
        self.get_custom_field_data()

    def display_working_directory(self, directory):
        self.labelWorkingDirectory.setText(directory)

    def display_quick_save(self):
        self.quick_save_frame.show()
        QtCore.QTimer.singleShot(500, self.quick_save_frame.hide)

    def get_custom_field_data(self):
        self.load_custom_data.emit(self.canvas.get_custom_field_data())

    def hide_custom_fields(self, hide):
        if hide is True:
            self.frameCustomField.hide()
        else:
            self.frameCustomField.show()

    def select_folder(self):
        name = QtWidgets.QFileDialog.getExistingDirectory(
            self, 'Select image folder', self.canvas.directory)
        if name != '':
            self.canvas.load([QtCore.QUrl('file:{}'.format(name))])

    def update_coordinates(self, text):
        x = self.lineEditX.text()
        y = self.lineEditY.text()
        self.canvas.save_coordinates(x, y)
Ejemplo n.º 15
0
class GUI_PyQt(QtCore.QObject):

    config = None
    gui_config = None
    logger = None
    app = None
    style = None

    stack_widget = None
    main_page = None
    main_page_index = 0
    altitude_graph_widget = None
    acc_graph_widget = None
    performance_graph_widget = None
    course_profile_graph_widget = None
    simple_map_widget = None
    cuesheet_widget = None
    multi_scan_widget = None

    display_buffer = None

    #for long press
    lap_button_count = 0
    start_button_count = 0

    #signal
    signal_next_button = QtCore.pyqtSignal(int)
    signal_prev_button = QtCore.pyqtSignal(int)
    signal_menu_button = QtCore.pyqtSignal(int)
    signal_menu_back_button = QtCore.pyqtSignal()
    signal_get_screenshot = QtCore.pyqtSignal()

    def __init__(self, config):
        super().__init__()
        self.config = config
        self.config.gui = self
        self.gui_config = GUI_Config(config)
        #from other program, call self.config.gui.style
        self.style = PyQtStyle()
        self.logger = self.config.logger
        try:
            signal.signal(signal.SIGTERM, self.quit_by_ctrl_c)
            signal.signal(signal.SIGINT, self.quit_by_ctrl_c)
            signal.signal(signal.SIGQUIT, self.quit_by_ctrl_c)
            signal.signal(signal.SIGHUP, self.quit_by_ctrl_c)
        except:
            pass

        self.display_buffer = QtCore.QBuffer()

        self.init_window()

    def quit_by_ctrl_c(self, signal, frame):
        self.quit()

    def quit(self):
        self.config.quit()
        self.app.quit()

    def init_window(self):
        self.app = QtWidgets.QApplication(sys.argv)

        self.icon_dir = ""
        if self.config.G_IS_RASPI:
            self.icon_dir = self.config.G_INSTALL_PATH

        #self.main_window
        #  stack_widget
        #    splash_widget
        #    main_widget
        #      main_layout
        #        main_page
        #        button_box_widget
        #    menu_widget

        time_profile = [
            datetime.now(),
        ]  #for time profile
        self.main_window = MyWindow()
        self.main_window.set_config(self.config)
        self.main_window.set_gui(self)
        self.main_window.setWindowTitle(self.config.G_PRODUCT)
        self.main_window.setMinimumSize(self.config.G_WIDTH,
                                        self.config.G_HEIGHT)
        self.main_window.show()
        self.set_color()

        #base stack_widget
        self.stack_widget = QtWidgets.QStackedWidget(self.main_window)
        self.main_window.setCentralWidget(self.stack_widget)
        self.stack_widget.setContentsMargins(0, 0, 0, 0)

        #default font
        res = QtGui.QFontDatabase.addApplicationFont(
            'fonts/Yantramanav/Yantramanav-Black.ttf')
        if res != -1:
            font_name = QtGui.QFontDatabase.applicationFontFamilies(res)[0]
            self.stack_widget.setStyleSheet(
                "font-family: {}".format(font_name))
            print("add font:", font_name)

        #Additional font from setting.conf
        if self.config.G_FONT_FULLPATH != "":
            res = QtGui.QFontDatabase.addApplicationFont(
                self.config.G_FONT_FULLPATH)
            if res != -1:
                self.config.G_FONT_NAME = QtGui.QFontDatabase.applicationFontFamilies(
                    res)[0]
                #self.stack_widget.setStyleSheet("font-family: {}".format(self.config.G_FONT_NAME))
                print("add font:", self.config.G_FONT_NAME)

        #self.stack_widget.setWindowFlags(QtCore.Qt.FramelessWindowHint)

        #elements
        #splash
        self.splash_widget = QtWidgets.QWidget(self.stack_widget)
        self.splash_widget.setContentsMargins(0, 0, 0, 0)
        #main
        self.main_widget = QtWidgets.QWidget(self.stack_widget)
        self.main_widget.setContentsMargins(0, 0, 0, 0)
        #menu top
        self.menu_widget = TopMenuWidget(self.stack_widget, "Settings",
                                         self.config)
        self.menu_widget.setContentsMargins(0, 0, 0, 0)
        #ANT+ menu
        self.ant_menu_widget = ANTMenuWidget(self.stack_widget, "ANT+ Sensors",
                                             self.config)
        self.ant_menu_widget.setContentsMargins(0, 0, 0, 0)
        #ANT+ detail
        self.ant_detail_widget = ANTDetailWidget(self.stack_widget,
                                                 "ANT+ Detail", self.config)
        self.ant_detail_widget.setContentsMargins(0, 0, 0, 0)
        #adjust altitude
        self.adjust_wheel_circumference_widget = AdjustWheelCircumferenceWidget(
            self.stack_widget, "Wheel Size (Circumference)", self.config)
        self.adjust_wheel_circumference_widget.setContentsMargins(0, 0, 0, 0)
        #adjust altitude
        self.adjust_atitude_widget = AdjustAltitudeWidget(
            self.stack_widget, "Adjust Altitude", self.config)
        self.adjust_atitude_widget.setContentsMargins(0, 0, 0, 0)
        #Debug log viewer
        self.debug_log_viewer_widget = DebugLogViewerWidget(
            self.stack_widget, "Debug Log Viewer", self.config)
        self.debug_log_viewer_widget.setContentsMargins(0, 0, 0, 0)
        #integrate
        self.stack_widget.addWidget(self.splash_widget)
        self.stack_widget.addWidget(self.main_widget)
        self.stack_widget.addWidget(self.menu_widget)
        self.stack_widget.addWidget(self.ant_menu_widget)
        self.stack_widget.addWidget(self.ant_detail_widget)
        self.stack_widget.addWidget(self.adjust_wheel_circumference_widget)
        self.stack_widget.addWidget(self.adjust_atitude_widget)
        self.stack_widget.addWidget(self.debug_log_viewer_widget)
        self.stack_widget.setCurrentIndex(1)

        #main layout
        self.main_layout = QtWidgets.QVBoxLayout(self.main_widget)
        self.main_layout.setContentsMargins(0, 0, 0, 0)
        self.main_layout.setSpacing(0)
        self.main_widget.setLayout(self.main_layout)

        #main Widget
        self.main_page = QtWidgets.QStackedWidget(self.main_widget)
        self.main_page.setContentsMargins(0, 0, 0, 0)

        time_profile.append(datetime.now())

        for k in self.gui_config.G_LAYOUT:
            if not self.gui_config.G_LAYOUT[k]["STATUS"]:
                continue
            if "LAYOUT" in self.gui_config.G_LAYOUT[k]:
                self.main_page.addWidget(
                    ValuesWidget(self.main_page, self.config,
                                 self.gui_config.G_LAYOUT[k]["LAYOUT"]))
            else:
                if k == "ALTITUDE_GRAPH":
                    self.altitude_graph_widget = pyqt_graph_debug.AltitudeGraphWidget(
                        self.main_page, self.config)
                    self.main_page.addWidget(self.altitude_graph_widget)
                elif k == "ACC_GRAPH":
                    self.acc_graph_widget = pyqt_graph_debug.AccelerationGraphWidget(
                        self.main_page, self.config)
                    self.main_page.addWidget(self.acc_graph_widget)
                elif k == "PERFORMANCE_GRAPH":
                    self.performance_graph_widget = pyqt_graph.PerformanceGraphWidget(
                        self.main_page, self.config)
                    self.main_page.addWidget(self.performance_graph_widget)
                elif k == "COURSE_PROFILE_GRAPH" and os.path.exists(
                        self.config.G_COURSE_FILE
                ) and self.config.G_COURSE_INDEXING:
                    self.course_profile_graph_widget = pyqt_graph.CourseProfileGraphWidget(
                        self.main_page, self.config)
                    self.main_page.addWidget(self.course_profile_graph_widget)
                elif k == "SIMPLE_MAP":
                    self.simple_map_widget = pyqt_graph.SimpleMapWidget(
                        self.main_page, self.config)
                    self.main_page.addWidget(self.simple_map_widget)
                elif k == "CUESHEET" and len(self.config.logger.course.point_name) > 0 and self.config.G_COURSE_INDEXING and \
                  self.config.G_CUESHEET_DISPLAY_NUM > 0:
                    self.cuesheet_widget = pyqt_graph.CueSheetWidget(
                        self.main_page, self.config)
                    self.main_page.addWidget(self.cuesheet_widget)
                elif k == "MULTI_SCAN":
                    self.multi_scan_widget = pyqt_multiscan.MultiScanWidget(
                        self.main_page, self.config)
                    self.main_page.addWidget(self.multi_scan_widget)

        time_profile.append(datetime.now())

        #button
        self.button_box_widget = ButtonBoxWidget(self.main_widget, self.config)
        self.button_box_widget.start_button.clicked.connect(
            self.gui_start_and_stop_quit)
        self.button_box_widget.lap_button.clicked.connect(self.gui_lap_reset)
        self.button_box_widget.menu_button.clicked.connect(self.goto_menu)
        self.button_box_widget.scrollnext_button.clicked.connect(
            self.scroll_next)
        self.button_box_widget.scrollprev_button.clicked.connect(
            self.scroll_prev)

        #physical button
        self.signal_next_button.connect(self.scroll)
        self.signal_prev_button.connect(self.scroll)
        self.signal_menu_button.connect(self.change_menu_page)
        self.signal_menu_back_button.connect(self.change_menu_back)
        #other
        self.signal_get_screenshot.connect(self.screenshot)

        #integrate main_layout
        self.main_layout.addWidget(self.main_page)
        if not self.config.G_AVAILABLE_DISPLAY[self.config.G_DISPLAY]['touch']:
            self.button_box_widget.setVisible(False)
        else:
            self.main_layout.addWidget(self.button_box_widget)

        time_profile.append(datetime.now())  #for time profile

        #self.main_window.show()

        #fullscreen
        if self.config.G_FULLSCREEN:
            self.main_window.showFullScreen()

        self.on_change_main_page(self.main_page_index)

        diff_label = ["base", "widget", "button"]
        print("  gui_pyqt:")
        for i in range(len(time_profile)):
            if i == 0: continue
            t = "{0:.4f}".format(
                (time_profile[i] - time_profile[i - 1]).total_seconds())
            print("   ", '{:<13}'.format(diff_label[i - 1]), ":", t)

        self.app.exec()
        #exit this line
        #sys.exit(self.app.exec_())

    #for stack_widget page transition
    def on_change_main_page(self, index):
        self.main_page.widget(self.main_page_index).stop()
        self.main_page.widget(index).start()
        self.main_page_index = index

    #def send_key(self, e):
    #  if e.key() == QtCore.Qt.Key_N:
    #    self.scroll_next()

    def start_and_stop_manual(self):
        self.logger.start_and_stop_manual()

    def count_laps(self):
        self.logger.count_laps()

    def reset_count(self):
        self.logger.reset_count()

    def press_key(self, key):
        e_press = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, key,
                                  QtCore.Qt.NoModifier, None)
        e_release = QtGui.QKeyEvent(QtCore.QEvent.KeyRelease, key,
                                    QtCore.Qt.NoModifier, None)
        QtCore.QCoreApplication.postEvent(QtWidgets.QApplication.focusWidget(),
                                          e_press)
        QtCore.QCoreApplication.postEvent(QtWidgets.QApplication.focusWidget(),
                                          e_release)

    def press_tab(self):
        #self.press_key(QtCore.Qt.Key_Tab)
        self.main_page.widget(self.main_page_index).focusPreviousChild()

    def press_down(self):
        #self.press_key(QtCore.Qt.Key_Down)
        self.main_page.widget(self.main_page_index).focusNextChild()

    def press_space(self):
        self.press_key(QtCore.Qt.Key_Space)

    def scroll_next(self):
        self.signal_next_button.emit(1)

    def scroll_prev(self):
        self.signal_next_button.emit(-1)

    def enter_menu(self):
        i = self.stack_widget.currentIndex()
        if i == 1:
            #goto_menu:
            self.signal_menu_button.emit(2)
        elif i >= 2:
            #back
            self.back_menu()

    def back_menu(self):
        self.signal_menu_back_button.emit()

    def change_mode(self):
        #if displays MAP, change MAP_1, MAP_2, MAIN
        #check MAIN
        if self.stack_widget.currentIndex() != 1:
            return
        #check MAP
        w = self.main_page.widget(self.main_page.currentIndex())
        w_name = w.__class__.__name__
        b_m_g = self.config.G_BUTTON_MODE_GROUPS
        b_m_i = self.config.G_BUTTON_MODE_INDEX
        if w_name == 'SimpleMapWidget':
            #change_mode
            m = 'MAP'
            self.config.logger.sensor.sensor_i2c.change_button_mode(m)
            if b_m_g[m][b_m_i[m]] == "MAIN":
                w.lock_on()
            else:
                w.lock_off()

    def map_move_x_plus(self):
        self.map_method("move_x_plus")

    def map_move_x_minus(self):
        self.map_method("move_x_minus")

    def map_move_y_plus(self):
        self.map_method("move_y_plus")

    def map_move_y_minus(self):
        self.map_method("move_y_minus")

    def map_change_move(self):
        self.map_method("change_move")

    def map_zoom_plus(self):
        self.map_method("zoom_plus")

    def map_zoom_minus(self):
        self.map_method("zoom_minus")

    def map_search_route(self):
        self.map_method("search_route")

    def map_method(self, mode):
        w = self.main_page.widget(self.main_page.currentIndex())
        widget_name = w.__class__.__name__
        if widget_name == 'SimpleMapWidget':
            eval('w.signal_' + mode + '.emit()')

    def dummy(self):
        pass

    def scroll(self, delta):
        mod_index = self.main_page.currentIndex()
        while True:
            mod_index += delta
            if mod_index == self.main_page.count(): mod_index = 0
            elif mod_index == -1: mod_index = self.main_page.count() - 1
            if self.main_page.widget(mod_index).onoff == True: break
        self.on_change_main_page(mod_index)
        self.main_page.setCurrentIndex(mod_index)

    def get_screenshot(self):
        self.signal_get_screenshot.emit()

    def screenshot(self):
        date = datetime.now()
        print("screenshot")
        filename = date.strftime('%Y-%m-%d_%H-%M-%S.jpg')
        p = self.stack_widget.grab()
        p.save(self.config.G_SCREENSHOT_DIR + filename, 'jpg')

    def draw_display(self):
        if not self.config.logger.sensor.sensor_spi.send_display:
            return
        p = self.stack_widget.grab()
        self.display_buffer.open(QtCore.QBuffer.ReadWrite)
        p.save(self.display_buffer, 'BMP')
        self.config.logger.sensor.sensor_spi.update(
            io.BytesIO(self.display_buffer.data()))
        self.display_buffer.close()

    def gui_lap_reset(self):
        if self.button_box_widget.lap_button.isDown():
            if self.button_box_widget.lap_button._state == 0:
                self.button_box_widget.lap_button._state = 1
            else:
                self.lap_button_count += 1
                print('lap button pressing : ', self.lap_button_count)
                if self.lap_button_count == self.config.G_BUTTON_LONG_PRESS:
                    print('reset')
                    self.logger.reset_count()
                    self.simple_map_widget.reset_track()
                    self.lap_button_count = 0
        elif self.button_box_widget.lap_button._state == 1:
            self.button_box_widget.lap_button._state = 0
            self.lap_button_count = 0
        else:
            self.logger.count_laps()

    def gui_start_and_stop_quit(self):
        if self.button_box_widget.start_button.isDown():
            if self.button_box_widget.start_button._state == 0:
                self.button_box_widget.start_button._state = 1
            else:
                self.start_button_count += 1
                print('start button pressing : ', self.start_button_count)
                if self.start_button_count == self.config.G_BUTTON_LONG_PRESS:
                    print('quit or poweroff')
                    self.quit()
        elif self.button_box_widget.start_button._state == 1:
            self.button_box_widget.start_button._state = 0
            self.start_button_count = 0
        else:
            self.logger.start_and_stop_manual()

    def change_start_stop_button(self, status):
        icon = QtGui.QIcon(self.icon_dir + 'img/pause_white.png')
        if status == "START":
            icon = QtGui.QIcon(self.icon_dir + 'img/next_white.png')
        self.button_box_widget.start_button.setIcon(icon)
        #in mip display, setIcon seems not to occur paint event
        self.draw_display()

    def brightness_control(self):
        self.config.logger.sensor.sensor_spi.brightness_control()

    def change_menu_page(self, page):
        self.stack_widget.setCurrentIndex(page)

    def change_menu_back(self):
        self.stack_widget.currentWidget().back()

    def goto_menu(self):
        self.change_menu_page(self.gui_config.G_GUI_INDEX['menu'])

    def set_color(self, daylight=True):
        if daylight:
            self.main_window.setStyleSheet(
                "color: black; background-color: white")
        else:
            self.main_window.setStyleSheet(
                "color: white; background-color: #222222")
Ejemplo n.º 16
0
class CentralGraphicsView(QtWidgets.QGraphicsView):
    add_point = QtCore.pyqtSignal(QtCore.QPointF)
    drop_complete = QtCore.pyqtSignal(list)
    region_selected = QtCore.pyqtSignal(QtCore.QRectF)
    delete_selection = QtCore.pyqtSignal()
    relabel_selection = QtCore.pyqtSignal()
    toggle_points = QtCore.pyqtSignal()
    toggle_grid = QtCore.pyqtSignal()
    switch_class = QtCore.pyqtSignal(int)

    def __init__(self, parent=None):
        QtWidgets.QGraphicsView.__init__(self, parent)
        self.setMouseTracking(True)
        self.setAcceptDrops(True)
        self.shift = False
        self.ctrl = False
        self.alt = False
        self.delay = 0
        self.setViewportUpdateMode(
            QtWidgets.QGraphicsView.ViewportUpdateMode.FullViewportUpdate)

    def enterEvent(self, event):
        self.setFocus()

    def dragEnterEvent(self, event):
        event.setAccepted(True)

    def dragMoveEvent(self, event):
        pass

    def dropEvent(self, event):
        if len(event.mimeData().urls()) > 0:
            self.drop_complete.emit(event.mimeData().urls())

    def image_loaded(self, directory, file_name):
        self.resetTransform()
        self.fitInView(self.scene().itemsBoundingRect(),
                       QtCore.Qt.AspectRatioMode.KeepAspectRatio)
        self.setSceneRect(self.scene().itemsBoundingRect())

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key.Key_Alt:
            self.alt = True
        elif event.key() == QtCore.Qt.Key.Key_Control:
            self.ctrl = True
        elif event.key() == QtCore.Qt.Key.Key_Shift:
            self.shift = True
        elif event.key() == QtCore.Qt.Key.Key_Delete or event.key(
        ) == QtCore.Qt.Key.Key_Backspace:
            self.delete_selection.emit()
        elif event.key() == QtCore.Qt.Key.Key_R:
            self.relabel_selection.emit()
        elif event.key() == QtCore.Qt.Key.Key_D:
            self.toggle_points.emit()
        elif event.key() == QtCore.Qt.Key.Key_G:
            self.toggle_grid.emit()
        elif event.key() == QtCore.Qt.Key.Key_1:
            self.switch_class.emit(0)
        elif event.key() == QtCore.Qt.Key.Key_2:
            self.switch_class.emit(1)
        elif event.key() == QtCore.Qt.Key.Key_3:
            self.switch_class.emit(2)
        elif event.key() == QtCore.Qt.Key.Key_4:
            self.switch_class.emit(3)
        elif event.key() == QtCore.Qt.Key.Key_5:
            self.switch_class.emit(4)
        elif event.key() == QtCore.Qt.Key.Key_6:
            self.switch_class.emit(5)
        elif event.key() == QtCore.Qt.Key.Key_7:
            self.switch_class.emit(6)
        elif event.key() == QtCore.Qt.Key.Key_8:
            self.switch_class.emit(7)
        elif event.key() == QtCore.Qt.Key.Key_9:
            self.switch_class.emit(8)
        elif event.key() == QtCore.Qt.Key.Key_0:
            self.switch_class.emit(9)

    def keyReleaseEvent(self, event):
        if event.key() == QtCore.Qt.Key.Key_Alt:
            self.alt = False
        elif event.key() == QtCore.Qt.Key.Key_Control:
            self.ctrl = False
        elif event.key() == QtCore.Qt.Key.Key_Shift:
            self.shift = False

    def mouseMoveEvent(self, event):
        QtWidgets.QGraphicsView.mouseMoveEvent(self, event)

    def mousePressEvent(self, event):
        if self.ctrl:
            self.add_point.emit(self.mapToScene(event.pos()))
        elif self.shift:
            self.setDragMode(QtWidgets.QGraphicsView.DragMode.RubberBandDrag)
            QtWidgets.QGraphicsView.mousePressEvent(self, event)
        else:
            self.setDragMode(QtWidgets.QGraphicsView.DragMode.ScrollHandDrag)
            QtWidgets.QGraphicsView.mousePressEvent(self, event)

    def mouseReleaseEvent(self, event):
        if self.dragMode() == QtWidgets.QGraphicsView.DragMode.RubberBandDrag:
            rect = self.rubberBandRect()
            self.region_selected.emit(self.mapToScene(rect).boundingRect())
            QtWidgets.QGraphicsView.mouseReleaseEvent(self, event)
        self.setDragMode(QtWidgets.QGraphicsView.DragMode.NoDrag)

    def resizeEvent(self, event):
        self.resize_image()

    def resize_image(self):
        vsb = self.verticalScrollBar().isVisible()
        hsb = self.horizontalScrollBar().isVisible()
        if not (vsb or hsb):
            self.fitInView(self.scene().itemsBoundingRect(),
                           QtCore.Qt.AspectRatioMode.KeepAspectRatio)
            self.setSceneRect(self.scene().itemsBoundingRect())

    def wheelEvent(self, event):
        if len(self.scene().items()) > 0:
            if event.angleDelta().y() > 0:
                self.zoom_in()
            else:
                self.zoom_out()

    def zoom_in(self):
        self.scale(1.1, 1.1)
        # Fix for MacOS and PyQt5 > v5.10
        self.repaint()

    def zoom_out(self):
        self.scale(0.9, 0.9)
        # Fix for MacOS and PyQt5 > v5.10
        self.repaint()
Ejemplo n.º 17
0
class Mythread(QtCore.QThread):
    # 定义信号,定义参数为str类型
    signal_one = QtCore.pyqtSignal(int)

    def __init__(self, parent=None):
        super().__init__(parent)

        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36",
            "Referer": "https://www.mzitu.com/"
        }
        self.url = None
        self.max_page_num = 0
        self.dir = None

    def get_max_page_num(self,url):
        response = requests.get(url, headers=self.headers)
        response.encoding = "utf-8"
        page = BeautifulSoup(response.text, "html.parser")
        ### 获得节点的src属性
        img_url = page.find('div', class_="pagenavi")
        try:
            lasturl = img_url.find_all('a')[-2].get('href')
            self.max_page_num = int(lasturl.split("/")[-1])
            return  self.max_page_num
        except:
            print("查找照片个数失败")

    def download_current_img(self,url):
        #下载图片
        response = requests.get(url,headers=self.headers)
        response.encoding = "utf-8"
        #print(response.text)
        page = BeautifulSoup(response.text,"html.parser")
        ### 获得节点的src属性
        img_url = page.find('div',class_='main-image').img['src']
        #下载
        img_name= img_url.split("/")[-1]
        response_img = requests.get(img_url, headers=self.headers)
        with open("%s/%s"%(self.dir,img_name), 'wb') as f:
            f.write(response_img.content)  # 图片内容写入文件
            f.close()
            print("url: %s  图片抓取成功:%s"%(img_url, img_name))


    def run(self):
        while True:
            # 爬虫图片
            if self.url:
                print("开始爬虫")
                self.signal_one.emit(0)
                num = self.get_max_page_num(self.url)
                for i in range(0,num+1):
                    if i == 0:
                        self.download_current_img(self.url)
                    elif i<100:
                        self.download_current_img(self.url + "/%02d" % (i))
                    else:
                        self.download_current_img(self.url + "/%03d" % (i))
                    self.signal_one.emit(int(i*100//num))
                self.url = None
                self.signal_one.emit(100)
                print("爬取完成")
Ejemplo n.º 18
0
class Canvas(QtWidgets.QGraphicsScene):
    image_loaded = QtCore.pyqtSignal(str, str)
    points_loaded = QtCore.pyqtSignal(str)
    directory_set = QtCore.pyqtSignal(str)
    fields_updated = QtCore.pyqtSignal(list)
    update_point_count = QtCore.pyqtSignal(str, str, int)
    metadata_imported = QtCore.pyqtSignal()

    def __init__(self):
        QtWidgets.QGraphicsScene.__init__(self)
        self.points = {}
        self.colors = {}
        self.coordinates = {}
        self.custom_fields = {'fields': [], 'data': {}}
        self.classes = []
        self.selection = []
        self.ui = {
            'grid': {
                'size': 200,
                'color': [255, 255, 255]
            },
            'point': {
                'radius': 25,
                'color': [255, 255, 0]
            }
        }

        self.directory = ''
        self.current_image_name = None
        self.current_class_name = None

        self.qt_image = None
        self.show_grid = True

        self.selected_pen = QtGui.QPen(
            QtGui.QBrush(QtCore.Qt.GlobalColor.red,
                         QtCore.Qt.BrushStyle.SolidPattern), 1)

    def add_class(self, class_name):
        if class_name not in self.classes:
            self.classes.append(class_name)
            self.classes.sort()
            self.colors[class_name] = QtGui.QColor(QtCore.Qt.GlobalColor.black)

    def add_custom_field(self, field_def):
        self.custom_fields['fields'].append(field_def)
        self.custom_fields['data'][field_def[0]] = {}
        self.fields_updated.emit(self.custom_fields['fields'])

    def add_point(self, point):
        if self.current_image_name is not None and self.current_class_name is not None:
            if self.current_class_name not in self.points[
                    self.current_image_name]:
                self.points[self.current_image_name][
                    self.current_class_name] = []
            display_radius = self.ui['point']['radius']
            active_color = QtGui.QColor(self.ui['point']['color'][0],
                                        self.ui['point']['color'][1],
                                        self.ui['point']['color'][2])
            active_brush = QtGui.QBrush(active_color,
                                        QtCore.Qt.BrushStyle.SolidPattern)
            active_pen = QtGui.QPen(active_brush, 2)
            self.points[self.current_image_name][
                self.current_class_name].append(point)
            self.addEllipse(
                QtCore.QRectF(point.x() - ((display_radius - 1) / 2),
                              point.y() - ((display_radius - 1) / 2),
                              display_radius, display_radius), active_pen,
                active_brush)
            self.update_point_count.emit(
                self.current_image_name, self.current_class_name,
                len(self.points[self.current_image_name][
                    self.current_class_name]))

    def clear_grid(self):
        for graphic in self.items():
            if type(graphic) == QtWidgets.QGraphicsLineItem:
                self.removeItem(graphic)

    def clear_points(self):
        for graphic in self.items():
            if type(graphic) == QtWidgets.QGraphicsEllipseItem:
                self.removeItem(graphic)

    def delete_selected_points(self):
        if self.current_image_name is not None:
            points = self.points[self.current_image_name]
            for class_name, point in self.selection:
                points[class_name].remove(point)
                self.update_point_count.emit(
                    self.current_image_name, class_name,
                    len(self.points[self.current_image_name][class_name]))
            self.selection = []
            self.display_points()

    def delete_custom_field(self, field):
        if field in self.custom_fields['data']:
            self.custom_fields['data'].pop(field)
            index = -1
            for i, (field_name, _) in enumerate(self.custom_fields['fields']):
                if field_name == field:
                    index = i
            if index >= 0:
                self.custom_fields['fields'].pop(index)
            self.fields_updated.emit(self.custom_fields['fields'])

    def display_grid(self):
        self.clear_grid()
        if self.current_image_name and self.show_grid:
            grid_color = QtGui.QColor(self.ui['grid']['color'][0],
                                      self.ui['grid']['color'][1],
                                      self.ui['grid']['color'][2])
            grid_size = self.ui['grid']['size']
            rect = self.itemsBoundingRect()
            brush = QtGui.QBrush(grid_color, QtCore.Qt.BrushStyle.SolidPattern)
            pen = QtGui.QPen(brush, 1)
            for x in range(grid_size, int(rect.width()), grid_size):
                line = QtCore.QLineF(x, 0.0, x, rect.height())
                self.addLine(line, pen)
            for y in range(grid_size, int(rect.height()), grid_size):
                line = QtCore.QLineF(0.0, y, rect.width(), y)
                self.addLine(line, pen)

    def display_points(self):
        self.clear_points()
        if self.current_image_name in self.points:
            display_radius = self.ui['point']['radius']
            active_color = QtGui.QColor(self.ui['point']['color'][0],
                                        self.ui['point']['color'][1],
                                        self.ui['point']['color'][2])
            active_brush = QtGui.QBrush(active_color,
                                        QtCore.Qt.BrushStyle.SolidPattern)
            active_pen = QtGui.QPen(active_brush, 2)
            for class_name in self.points[self.current_image_name]:
                points = self.points[self.current_image_name][class_name]
                brush = QtGui.QBrush(self.colors[class_name],
                                     QtCore.Qt.BrushStyle.SolidPattern)
                pen = QtGui.QPen(brush, 2)
                for point in points:
                    if class_name == self.current_class_name:
                        self.addEllipse(
                            QtCore.QRectF(
                                point.x() - ((display_radius - 1) / 2),
                                point.y() - ((display_radius - 1) / 2),
                                display_radius, display_radius), active_pen,
                            active_brush)
                    else:
                        self.addEllipse(
                            QtCore.QRectF(
                                point.x() - ((display_radius - 1) / 2),
                                point.y() - ((display_radius - 1) / 2),
                                display_radius, display_radius), pen, brush)

    def export_counts(self, file_name, survey_id):
        if self.current_image_name is not None:
            file = open(file_name, 'w')
            output = 'survey id,image'
            for class_name in self.classes:
                output += ',' + class_name
            output += ",x,y"
            for field_name, _ in self.custom_fields['fields']:
                output += ',{}'.format(field_name)
            output += '\n'
            file.write(output)
            for image in self.points:
                output = survey_id + ',' + image
                for class_name in self.classes:
                    if class_name in self.points[image]:
                        output += ',' + str(len(
                            self.points[image][class_name]))
                    else:
                        output += ',0'
                if image in self.coordinates:
                    output += ',' + self.coordinates[image]['x']
                    output += ',' + self.coordinates[image]['y']
                else:
                    output += ',,'
                for field_name, _ in self.custom_fields['fields']:
                    if image in self.custom_fields['data'][field_name]:
                        output += ',{}'.format(
                            self.custom_fields['data'][field_name][image])
                    else:
                        output += ','
                output += "\n"
                file.write(output)
            file.close()

    def export_points(self, file_name, survey_id):
        if self.current_image_name is not None:
            file = open(file_name, 'w')
            output = 'survey id,image,class,x,y'
            file.write(output)
            for image in self.points:
                for class_name in self.classes:
                    if class_name in self.points[image]:
                        for point in self.points[image][class_name]:
                            output = '\n{},{},{},{},{}'.format(
                                survey_id, image, class_name, point.x(),
                                point.y())
                            file.write(output)
            file.close()

    def get_custom_field_data(self):
        data = {}
        if self.current_image_name is not None:
            for field_def in self.custom_fields['fields']:
                if self.current_image_name in self.custom_fields['data'][
                        field_def[0]]:
                    data[field_def[0]] = self.custom_fields['data'][
                        field_def[0]][self.current_image_name]
                else:
                    data[field_def[0]] = ''
        return data

    def import_metadata(self, file_name):
        file = open(file_name, 'r')
        data = json.load(file)
        file.close()

        # Backward compat
        if 'custom_fields' in data:
            self.custom_fields = data['custom_fields']
        else:
            self.custom_fields = {'fields': [], 'data': {}}
        if 'ui' in data:
            self.ui = data['ui']
        else:
            self.ui = {
                'grid': {
                    'size': 200,
                    'color': [255, 255, 255]
                },
                'point': {
                    'radius': 25,
                    'color': [255, 255, 0]
                }
            }
        # End Backward compat

        self.colors = data['colors']
        for class_name in data['colors']:
            self.colors[class_name] = QtGui.QColor(self.colors[class_name][0],
                                                   self.colors[class_name][1],
                                                   self.colors[class_name][2])
        self.classes = data['classes']
        self.fields_updated.emit(self.custom_fields['fields'])
        self.points_loaded.emit('')
        self.metadata_imported.emit()

    def load(self, drop_list):
        peek = drop_list[0].toLocalFile()
        if os.path.isdir(peek):
            if self.directory == '':
                # strip off trailing sep from path
                osx_hack = os.path.join(peek, 'OSX')
                self.directory = os.path.split(osx_hack)[0]
                # end
                self.directory_set.emit(self.directory)
                files = glob.glob(os.path.join(self.directory, '*'))
                image_format = [".jpg", ".jpeg", ".png", ".tif"]
                f = (lambda x: os.path.splitext(x)[1].lower() in image_format)
                image_list = list(filter(f, files))
                image_list = sorted(image_list)
                self.load_images(image_list)
            else:
                QtWidgets.QMessageBox.warning(
                    self.parent(), 'Warning',
                    'Working directory already set. Load canceled.',
                    QtWidgets.QMessageBox.Ok)
        else:
            base_path = os.path.split(peek)[0]
            for entry in drop_list:
                file_name = entry.toLocalFile()
                path = os.path.split(file_name)[0]
                error = False
                message = ''
                if os.path.isdir(file_name):
                    error = True
                    message = 'Mix of files and directories detected. Load canceled.'
                if base_path != path:
                    error = True
                    message = 'Files from multiple directories detected. Load canceled.'
                if self.directory != '' and self.directory != path:
                    error = True
                    message = 'Image originated outside current working directory. Load canceled.'
                if error:
                    QtWidgets.QMessageBox.warning(self.parent(), 'Warning',
                                                  message,
                                                  QtWidgets.QMessageBox.Ok)
                    return None
            self.directory = base_path
            self.directory_set.emit(self.directory)
            self.load_images(drop_list)

    def load_image(self, in_file_name):
        Image.MAX_IMAGE_PIXELS = 1000000000
        file_name = in_file_name
        if type(file_name) == QtCore.QUrl:
            file_name = in_file_name.toLocalFile()

        if self.directory == '':
            self.directory = os.path.split(file_name)[0]
            self.directory_set.emit(self.directory)

        if self.directory == os.path.split(file_name)[0]:
            QtWidgets.QApplication.setOverrideCursor(
                QtCore.Qt.CursorShape.WaitCursor)
            self.selection = []
            self.clear()
            self.current_image_name = os.path.split(file_name)[1]
            if self.current_image_name not in self.points:
                self.points[self.current_image_name] = {}
            try:
                img = Image.open(file_name)
                channels = len(img.getbands())
                array = np.array(img)
                img.close()
                if array.shape[0] > 10000 or array.shape[1] > 10000:
                    # Make smaller tiles to save memory
                    stride = 100
                    max_stride = (array.shape[1] // stride) * stride
                    tail = array.shape[1] - max_stride
                    tile = np.zeros((array.shape[0], stride, array.shape[2]),
                                    dtype=np.uint8)
                    for s in range(0, max_stride, stride):
                        tile[:, :] = array[:, s:s + stride]
                        qt_image = QtGui.QImage(
                            tile.data, tile.shape[1], tile.shape[0],
                            QtGui.QImage.Format.Format_RGB888)
                        pixmap = QtGui.QPixmap.fromImage(qt_image)
                        item = self.addPixmap(pixmap)
                        item.moveBy(s, 0)
                    # Fix for windows, thin slivers at the end cause the app to hang. QImage bug?
                    if tail > 0:
                        tile2 = np.ones(
                            (array.shape[0], stride, array.shape[2]),
                            dtype=np.uint8) * 255
                        tile2[:, 0:tail] = array[:, max_stride:array.shape[1]]
                        qt_image = QtGui.QImage(
                            tile2.data, tile2.shape[1], tile2.shape[0],
                            QtGui.QImage.Format.Format_RGB888)
                        pixmap = QtGui.QPixmap.fromImage(qt_image)
                        item = self.addPixmap(pixmap)
                        item.moveBy(max_stride, 0)
                else:
                    if channels == 1:
                        self.qt_image = QtGui.QImage(
                            array.data, array.shape[1], array.shape[0],
                            QtGui.QImage.Format.Format_Grayscale8)
                    else:
                        # Apply basic min max stretch to the image
                        for chan in range(channels):
                            array[:, :,
                                  chan] = np.interp(array[:, :, chan],
                                                    (array[:, :, chan].min(),
                                                     array[:, :, chan].max()),
                                                    (0, 255))
                        bpl = int(array.nbytes / array.shape[0])
                        if array.shape[2] == 4:
                            self.qt_image = QtGui.QImage(
                                array.data, array.shape[1], array.shape[0],
                                QtGui.QImage.Format.Format_RGBA8888)
                        else:
                            self.qt_image = QtGui.QImage(
                                array.data, array.shape[1], array.shape[0],
                                bpl, QtGui.QImage.Format.Format_RGB888)
                    self.pixmap = QtGui.QPixmap.fromImage(self.qt_image)
                    self.addPixmap(self.pixmap)
            except FileNotFoundError:
                QtWidgets.QMessageBox.critical(
                    None, 'File Not Found',
                    '{} is not in the same folder as the point file.'.format(
                        self.current_image_name))
                self.image_loaded.emit(self.directory, self.current_image_name)
            self.image_loaded.emit(self.directory, self.current_image_name)
            self.display_points()
            self.display_grid()
            QtWidgets.QApplication.restoreOverrideCursor()

    def load_images(self, images):
        for file in images:
            file_name = file
            if type(file) == QtCore.QUrl:
                file_name = file.toLocalFile()

            image_name = os.path.split(file_name)[1]
            if image_name not in self.points:
                self.points[image_name] = {}
        if len(images) > 0:
            self.load_image(images[0])

    def load_points(self, file_name):
        file = open(file_name, 'r')
        self.directory = os.path.split(file_name)[0]
        self.directory_set.emit(self.directory)
        data = json.load(file)
        file.close()
        survey_id = data['metadata']['survey_id']

        # Backward compat
        if 'custom_fields' in data:
            self.custom_fields = data['custom_fields']
        else:
            self.custom_fields = {'fields': [], 'data': {}}
        if 'ui' in data:
            self.ui = data['ui']
        else:
            self.ui = {
                'grid': {
                    'size': 200,
                    'color': [255, 255, 255]
                },
                'point': {
                    'radius': 25,
                    'color': [255, 255, 0]
                }
            }
        # End Backward compat

        self.colors = data['colors']
        self.classes = data['classes']
        self.coordinates = data['metadata']['coordinates']
        self.points = {}
        if 'points' in data:
            self.points = data['points']

        for image in self.points:
            for class_name in self.points[image]:
                for p in range(len(self.points[image][class_name])):
                    point = self.points[image][class_name][p]
                    self.points[image][class_name][p] = QtCore.QPointF(
                        point['x'], point['y'])
        for class_name in data['colors']:
            self.colors[class_name] = QtGui.QColor(self.colors[class_name][0],
                                                   self.colors[class_name][1],
                                                   self.colors[class_name][2])
        self.points_loaded.emit(survey_id)
        self.fields_updated.emit(self.custom_fields['fields'])
        path = os.path.split(file_name)[0]
        if self.points.keys():
            path = os.path.join(path, list(self.points.keys())[0])
            self.load_image(path)

    def package_points(self, survey_id):
        count = 0
        package = {
            'classes': [],
            'points': {},
            'colors': {},
            'metadata': {
                'survey_id': survey_id,
                'coordinates': self.coordinates
            },
            'custom_fields': self.custom_fields,
            'ui': self.ui
        }
        package['classes'] = self.classes
        for class_name in self.colors:
            r = self.colors[class_name].red()
            g = self.colors[class_name].green()
            b = self.colors[class_name].blue()
            package['colors'][class_name] = [r, g, b]
        for image in self.points:
            package['points'][image] = {}
            for class_name in self.points[image]:
                package['points'][image][class_name] = []
                src = self.points[image][class_name]
                dst = package['points'][image][class_name]
                for point in src:
                    p = {'x': point.x(), 'y': point.y()}
                    dst.append(p)
                    count += 1
        return (package, count)

    def relabel_selected_points(self):
        if self.current_class_name is not None:
            # for class_name, point in self.selection:
            for _, point in self.selection:
                self.add_point(point)
            self.delete_selected_points()

    def rename_class(self, old_class, new_class):
        index = self.classes.index(old_class)
        del self.classes[index]
        if new_class not in self.classes:
            self.colors[new_class] = self.colors.pop(old_class)
            self.classes.append(new_class)
            self.classes.sort()
        else:
            del self.colors[old_class]

        for image in self.points:
            if old_class in self.points[image] and new_class in self.points[
                    image]:
                self.points[image][new_class] += self.points[image].pop(
                    old_class)
            elif old_class in self.points[image]:
                self.points[image][new_class] = self.points[image].pop(
                    old_class)
        self.display_points()

    def reset(self, clear_image=False):
        self.points = {}
        self.colors = {}
        self.classes = []
        self.classes = []
        self.selection = []
        self.coordinates = {}
        self.custom_fields = {'fields': [], 'data': {}}

        self.clear()
        self.directory = ''
        self.current_image_name = ''
        self.current_class_name = None
        self.fields_updated.emit([])
        self.points_loaded.emit('')
        self.image_loaded.emit('', '')
        self.directory_set.emit('')

    def remove_class(self, class_name):
        index = self.classes.index(class_name)
        del self.colors[class_name]
        del self.classes[index]
        for image in self.points:
            if class_name in self.points[image]:
                del self.points[image][class_name]
        self.display_points()

    def save_coordinates(self, x, y):
        if self.current_image_name is not None:
            if self.current_image_name not in self.coordinates:
                self.coordinates[self.current_image_name] = {'x': '', 'y': ''}
            self.coordinates[self.current_image_name]['x'] = x
            self.coordinates[self.current_image_name]['y'] = y

    def save_custom_field_data(self, field, data):
        if self.current_image_name is not None:
            if self.current_image_name not in self.custom_fields['data'][
                    field]:
                self.custom_fields['data'][field][self.current_image_name] = ''
            self.custom_fields['data'][field][self.current_image_name] = data

    def save_points(self, file_name, survey_id):
        try:
            output, _ = self.package_points(survey_id)
            file = open(file_name, 'w')
            json.dump(output, file)
            file.close()
        except OSError:
            return False
        return True

    def select_points(self, rect):
        self.selection = []
        self.display_points()
        current = self.points[self.current_image_name]
        display_radius = self.ui['point']['radius']
        for class_name in current:
            for point in current[class_name]:
                if rect.contains(point):
                    offset = ((display_radius + 6) // 2)
                    self.addEllipse(
                        QtCore.QRectF(point.x() - offset,
                                      point.y() - offset, display_radius + 6,
                                      display_radius + 6), self.selected_pen)
                    self.selection.append((class_name, point))

    def set_current_class(self, class_index):
        if class_index is None or class_index >= len(self.classes):
            self.current_class_name = None
        else:
            self.current_class_name = self.classes[class_index]
        self.display_points()

    def set_grid_color(self, color):
        self.ui['grid']['color'] = [color.red(), color.green(), color.blue()]
        self.display_grid()

    def set_grid_size(self, size):
        self.ui['grid']['size'] = size
        self.display_grid()

    def set_point_color(self, color):
        self.ui['point']['color'] = [color.red(), color.green(), color.blue()]
        self.display_points()

    def set_point_radius(self, radius):
        self.ui['point']['radius'] = radius
        self.display_points()

    def toggle_grid(self, display):
        if display:
            self.show_grid = True
            self.display_grid()
        else:
            self.show_grid = False
            self.clear_grid()

    def toggle_points(self, display):
        if display:
            self.display_points()
            self.selection = []
        else:
            self.clear_points()
Ejemplo n.º 19
0
class BaseMapWidget(ScreenWidget):

    #map button
    button = {}
    button_name = [
        'lock', 'zoomup', 'zoomdown', 'left', 'right', 'up', 'down', 'go'
    ]
    lock_status = True
    button_press_count = {}

    #map position
    map_pos = {'x': np.nan, 'y': np.nan}  #center
    map_area = {
        'w': np.nan,
        'h': np.nan
    }  #witdh(longitude diff) and height(latitude diff)
    move_pos = {'x': 0, 'y': 0}

    #current point
    location = []
    point_color = {'fix': None, 'lost': None}

    #show range from zoom
    zoom = 2000  #[m] #for CourseProfileGraphWidget
    zoomlevel = 13  #for SimpleMapWidget

    #load course
    course_loaded = False

    #course points
    course_points_label = []

    #signal for physical button
    signal_move_x_plus = QtCore.pyqtSignal()
    signal_move_x_minus = QtCore.pyqtSignal()
    signal_move_y_plus = QtCore.pyqtSignal()
    signal_move_y_minus = QtCore.pyqtSignal()
    signal_zoom_plus = QtCore.pyqtSignal()
    signal_zoom_minus = QtCore.pyqtSignal()
    signal_change_move = QtCore.pyqtSignal()

    #for change_move
    move_adjust_mode = False
    move_factor = 1.0

    def init_extra(self):
        self.gps_values = self.config.logger.sensor.values['GPS']
        self.gps_sensor = self.config.logger.sensor.sensor_gps

        self.signal_move_x_plus.connect(self.move_x_plus)
        self.signal_move_x_minus.connect(self.move_x_minus)
        self.signal_move_y_plus.connect(self.move_y_plus)
        self.signal_move_y_minus.connect(self.move_y_minus)
        self.signal_zoom_plus.connect(self.zoom_plus)
        self.signal_zoom_minus.connect(self.zoom_minus)
        self.signal_change_move.connect(self.change_move)

    def setup_ui_extra(self):
        #main graph from pyqtgraph
        self.plot = pg.PlotWidget()
        self.plot.setBackground(None)
        self.plot.hideAxis('left')
        self.plot.hideAxis('bottom')

        #current point
        self.current_point = pg.ScatterPlotItem(pxMode=True)
        self.point_color = {
            #'fix':pg.mkBrush(color=(0,0,160,128)),
            'fix': pg.mkBrush(color=(0, 0, 255)),
            #'lost':pg.mkBrush(color=(96,96,96,128))
            'lost': pg.mkBrush(color=(128, 128, 128))
        }
        self.point = {
            'pos': [np.nan, np.nan],
            'size': 20,
            'pen': {
                'color': 'w',
                'width': 3
            },
            'brush': self.point_color['lost']
        }

        #self.plot.setMouseEnabled(x=False, y=False)
        #pg.setConfigOptions(antialias=True)

        #make buttons
        self.button['lock'] = QtWidgets.QPushButton("L")
        self.button['zoomup'] = QtWidgets.QPushButton("+")
        self.button['zoomdown'] = QtWidgets.QPushButton("-")
        self.button['left'] = QtWidgets.QPushButton("←")
        self.button['right'] = QtWidgets.QPushButton("→")
        self.button['up'] = QtWidgets.QPushButton("↑")
        self.button['down'] = QtWidgets.QPushButton("↓")
        self.button['go'] = QtWidgets.QPushButton("Go")
        for b in self.button_name:
            self.button[b].setStyleSheet(
                self.config.gui.style.G_GUI_PYQT_buttonStyle_map)

        self.button['lock'].clicked.connect(self.switch_lock)
        self.button['right'].clicked.connect(self.move_x_plus)
        self.button['left'].clicked.connect(self.move_x_minus)
        self.button['up'].clicked.connect(self.move_y_plus)
        self.button['down'].clicked.connect(self.move_y_minus)
        self.button['zoomdown'].clicked.connect(self.zoom_minus)
        self.button['zoomup'].clicked.connect(self.zoom_plus)

        #long press
        for key in ['lock']:
            self.button[key].setAutoRepeat(True)
            self.button[key].setAutoRepeatDelay(1000)
            self.button[key].setAutoRepeatInterval(1000)
            self.button[key]._state = 0
            self.button_press_count[key] = 0

        self.get_max_zoom()

    def make_item_layout(self):
        self.item_layout = {}

    def add_extra(self):
        pass

    #override disable
    def set_minimum_size(self):
        pass

    #for expanding row
    def resize_extra(self):
        n = self.layout.rowCount()
        h = int(self.size().height() / n)
        for i in range(n):
            self.layout.setRowMinimumHeight(i, h)

    def set_border(self):
        self.max_height = 1
        self.max_width = 3

    #def set_font_size(self):
    #  self.font_size = int(length / 8)

    def lock_off(self):
        self.lock_status = False

    def lock_on(self):
        self.lock_status = True

    def switch_lock(self):
        if self.lock_status:
            self.lock_off()
        else:
            self.lock_on()

    def change_move(self):
        if not self.move_adjust_mode:
            self.move_factor = 16
            self.move_adjust_mode = True
        else:
            self.move_factor = 1.0
            self.move_adjust_mode = False

    def move_x_plus(self):
        self.move_x(+self.zoom / 2)

    def move_x_minus(self):
        self.move_x(-self.zoom / 2)

    def move_y_plus(self):
        self.move_y(+self.zoom / 2)

    def move_y_minus(self):
        self.move_y(-self.zoom / 2)

    def move_x(self, delta):
        self.move_pos['x'] += delta
        self.update_extra()

    def move_y(self, delta):
        self.move_pos['y'] += delta
        self.update_extra()

    def zoom_plus(self):
        self.zoom /= 2
        self.zoomlevel += 1
        self.update_extra()

    def zoom_minus(self):
        self.zoom *= 2
        self.zoomlevel -= 1
        self.update_extra()

    def get_max_zoom(self):

        if len(self.config.logger.course.distance) == 0:
            return

        if self.config.G_MAX_ZOOM != 0:
            return
        z = self.zoom
        dist = self.config.logger.course.distance[-1]
        if (z / 1000 < dist):
            while (z / 1000 < dist):
                z *= 2
            z *= 2
        else:
            while (z / 1000 > dist):
                z /= 2
        self.config.G_MAX_ZOOM = z
        print("MAX_ZOOM", self.config.G_MAX_ZOOM, dist)

    def load_course(self):
        pass

    def update_extra(self):
        pass
Ejemplo n.º 20
0
class WorkerSignals(QtCore.QObject):
    result = QtCore.pyqtSignal(dict)
Ejemplo n.º 21
0
class DownLoadTaskWidget(QWidget):
    update_task_signa = QtCore.pyqtSignal()

    def __init__(self, task: DownloadTask):
        super().__init__()
        self.task = task
        constant.download_task_widget_map[task.chapterInfo.url] = self
        self.setMinimumHeight(40)
        self.setMaximumHeight(40)
        self.groupBox = QGroupBox(self)

        self.title = QLabel(self.groupBox)
        self.title.setText(task.comicInfo.title + task.chapterInfo.title)
        self.title.setGeometry(10, 5, 300, 20)
        # 下载进度
        self.schedule = QLabel(self.groupBox)
        self.schedule.setText(
            f"总页数:{len(self.task.imageInfos)}  已下载:{len(self.task.success)}  下载失败:{len(self.task.error)}")
        self.schedule.setGeometry(310, 5, 200, 20)
        # 进度条
        self.pbar = QProgressBar(self.groupBox)
        self.pbar.setGeometry(10, 25, 600, 10)
        self.pbar.setMinimum(0)
        self.pbar.setMaximum(len(task.imageInfos))
        self.pbar.setValue(0)
        self.update_task_signa.connect(self.update_task_thread)
        # 状态
        self.status = QLabel(self.groupBox)
        self.status.setGeometry(620, 12, 70, 20)
        self.status.setText("等待下载")
        # 按钮
        self.button = ButtonQLabel(self.groupBox)
        self.button.setGeometry(700, 12, 100, 20)
        self.button.setText("暂停")
        self.button.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.PointingHandCursor))
        button_font = QtGui.QFont()
        button_font.setUnderline(True)
        self.button.setFont(button_font)
        self.button.onclick(self.button_click)

    def change_status(self):
        # 按钮逻辑
        if self.task.status == 0:
            self.status.setText("等待下载")
            self.button.setVisible(False)
        elif self.task.status == 1:
            self.button.setVisible(True)
            self.button.setText("暂停")
            self.status.setText("正在下载")
        elif self.task.status == 2 or self.task.status == -3:
            self.button.setVisible(True)
            self.button.setText("继续")
            self.status.setText("暂停")
        elif self.task.status == -1:
            self.button.setVisible(False)
            self.status.setText("下载完成")
        elif self.task.status == -2:
            self.button.setVisible(True)
            self.button.setText("重试")
            self.status.setText("下载错误")

    def button_click(self):
        if self.task.status == 1:  # 正在下载,点击暂停
            self.task.status = 2
        elif self.task.status == 2 or self.task.status == -3:  # 暂停 ,点击等待下载,添加到队列
            self.task.status = 0
            constant.SERVICE.add_task(self.task)
        elif self.task.status == -2:  # 错误,点击重试
            constant.SERVICE.add_task(self.task)
        self.change_status()

    def update_task_thread(self):
        self.schedule.setText(
            f"总页数:{len(self.task.imageInfos)}  已下载:{len(self.task.success)}  下载失败:{len(self.task.error)}")
        self.pbar.setValue(len(self.task.success))
        self.change_status()

    def update_task(self, task: DownloadTask):
        self.task = task
        self.update_task_signa.emit()
Ejemplo n.º 22
0
class MainWindowWidget(QWidget):
    """
    主窗口界面 搜索框+tab页
    """
    load_comic_list_signa = QtCore.pyqtSignal(ComicInfo)

    def __init__(self, main_window: QWidget):
        super().__init__()
        self.search_callback = None
        # 主题空间 子组件都放这个Widget里
        self.centralWidget = QtWidgets.QWidget(main_window)
        self.centralWidget.setObjectName("centralWidget")
        # 搜索框
        self.souInput = QtWidgets.QLineEdit(self.centralWidget)
        self.souInput.setGeometry(QtCore.QRect(40, 30, 800, 30))
        font = QtGui.QFont()
        font.setPointSize(22)
        font.setKerning(True)
        font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferDefault)
        self.souInput.setFont(font)
        self.souInput.setObjectName("souInput")
        self.souInput.setText("龙珠")

        self.modBox = CheckableComboBox(self.centralWidget)
        self.modBox.setGeometry(QtCore.QRect(850, 30, 120, 30))
        for k in constant.mod_dist.keys():
            if k in constant.mod_list:
                self.modBox.addItem(QtCore.Qt.CheckState.Checked, k)
            else:
                self.modBox.addItem(QtCore.Qt.CheckState.Unchecked, k)

        # QTabWidget tab页签
        self.tabWidget = QtWidgets.QTabWidget(self.centralWidget)
        self.tabWidget.setGeometry(QtCore.QRect(40, 70, 944, 668))
        self.tabWidget.setTabsClosable(True)
        self.tabWidget.setObjectName("tabWidget")
        # 下载页面
        self.down_tab = QtWidgets.QWidget()
        self.down_tab.setStatusTip("")
        self.down_tab.setAutoFillBackground(False)
        self.down_tab.setObjectName("down_tab")
        self.tabWidget.addTab(self.down_tab, "下载列表")
        # 书架页面
        self.bookshelf_tab = QtWidgets.QWidget()
        self.bookshelf_tab.setObjectName("bookshelf_tab")
        self.tabWidget.addTab(self.bookshelf_tab, "书架")
        # 搜索结果页面
        self.search_tab = QtWidgets.QWidget()
        self.search_tab.setObjectName("search_tab")
        self.tabWidget.addTab(self.search_tab, "搜索结果")
        # None 空按钮,tab签右侧按钮,设置到前面
        tbr = self.tabWidget.tabBar().tabButton(0, QTabBar.ButtonPosition.RightSide)
        self.tabWidget.tabBar().setTabButton(0, QTabBar.ButtonPosition.LeftSide, tbr)
        self.tabWidget.tabBar().setTabButton(1, QTabBar.ButtonPosition.LeftSide, tbr)
        self.tabWidget.tabBar().setTabButton(2, QTabBar.ButtonPosition.LeftSide, tbr)
        # 启用关闭页签的功能
        self.tabWidget.tabCloseRequested.connect(self.tab_close)
        # 默认打开到书架
        self.tabWidget.setCurrentIndex(1)
        # 主体的centralWidget 放到主窗口中
        main_window.setCentralWidget(self.centralWidget)
        # 书架页
        self.bookshelfVBoxLayout = QVBoxLayout()
        self.bookshelfGroupBox = QGroupBox()
        self.bookshelfScroll = QScrollArea()
        self.bookshelfLayout = QVBoxLayout(self.bookshelf_tab)
        self.bookshelfVBoxLayout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)

        self.bookshelfGroupBox.setLayout(self.bookshelfVBoxLayout)
        self.bookshelfScroll.setWidget(self.bookshelfGroupBox)
        self.bookshelfScroll.setWidgetResizable(True)
        self.bookshelfLayout.addWidget(self.bookshelfScroll)
        # 搜索页
        self.searchVBoxLayout = QVBoxLayout()
        self.searchGroupBox = QGroupBox()
        self.searchScroll = QScrollArea()
        self.searchLayout = QVBoxLayout(self.search_tab)
        self.searchVBoxLayout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)

        self.searchGroupBox.setLayout(self.searchVBoxLayout)
        self.searchScroll.setWidget(self.searchGroupBox)
        self.searchScroll.setWidgetResizable(True)
        self.searchLayout.addWidget(self.searchScroll)
        # 下载页
        self.downVBoxLayout = QVBoxLayout()
        self.downGroupBox = QGroupBox()
        self.downScroll = QScrollArea()
        self.downLayout = QVBoxLayout(self.down_tab)
        self.downVBoxLayout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)

        self.downGroupBox.setLayout(self.downVBoxLayout)
        self.downScroll.setWidget(self.downGroupBox)
        self.downScroll.setWidgetResizable(True)
        self.downLayout.addWidget(self.downScroll)
        down_button_layout = QHBoxLayout()
        self.downLayout.addLayout(down_button_layout)
        down_button_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight)
        all_start = QPushButton()
        all_start.setText("全部开始")
        all_stop = QPushButton()
        all_stop.setText("全部停止")
        clear_done = QPushButton()
        clear_done.setText("清理已完成")

        down_button_layout.addWidget(all_start)
        down_button_layout.addWidget(all_stop)
        down_button_layout.addWidget(clear_done)

        self.souInput.returnPressed.connect(self.input_return_pressed)  # 回车搜索

        self.load_comic_list_signa.connect(self.search_load_comic_list)  # 更新ui的插槽

        self.bookshelf_load_comic_list()
        self.download_callback()

    def tab_close(self, index):
        """
        关闭tab,删掉缓存的列表
        :param index: tab索引
        :return:
        """
        self.tabWidget.removeTab(index)
        del constant.OPEN_TAB[index - 3]

    def input_return_pressed(self):
        """
        搜索框回车函数
        :return:
        """
        for i in range(self.searchVBoxLayout.count()):  # 清理显示的内容
            self.searchVBoxLayout.itemAt(i).widget().deleteLater()
        constant.mod_list.clear()
        for i in range(self.modBox.count()):
            if self.modBox.item_checked(i):
                constant.mod_list.add(self.modBox.model().item(i).text())
        if len(constant.mod_list) > 0:
            constant.SERVICE.search(self.souInput.text(), self.load_comic_list_signa.emit)  # 查询回调出发插槽
            self.tabWidget.setCurrentIndex(2)

    def search_load_comic_list(self, info: ComicInfo):
        """
        解析的漫画信息,通过回调到本方法,加载页面
        :param info:
        :return:
        """
        # 加载到展示视图,需要判断你,是否还是之前的搜索项
        if self.souInput.text() == info.searchKey:
            comic_info_widget = UIComicListWidget(info, self.tabWidget, self.downVBoxLayout)
            self.searchVBoxLayout.addWidget(comic_info_widget)

    def bookshelf_load_comic_list(self):
        for item in constant.downloaded_comic_map.values():
            comic_info_widget = UIComicListWidget(item, self.tabWidget, self.downVBoxLayout)
            self.bookshelfVBoxLayout.addWidget(comic_info_widget)

    def download_callback(self):
        for item in constant.downloaded_task_map.values():
            widget = DownLoadTaskWidget(item)
            widget.update_task(item)
            self.downVBoxLayout.addWidget(widget)
Ejemplo n.º 23
0
class UIComicInfoWidget(QWidget):
    load_chapter_list_signa = QtCore.pyqtSignal(ChapterInfo)
    load_download_task_signa = QtCore.pyqtSignal(DownloadTask)

    def __init__(self, comic_info: ComicInfo, down_v_box_layout: QVBoxLayout):
        super().__init__()
        self.comic_info = comic_info
        self.down_v_box_layout = down_v_box_layout
        self.img_label = QLabel(self)
        self.img_label.setScaledContents(True)
        img = QImage.fromData(comic_info.cover)
        w, h = image_resize(comic_info.cover, width=200)
        self.img_label.resize(QtCore.QSize(w, h))
        self.img_label.setGeometry(10, 10, w, h)
        self.img_label.setPixmap(QPixmap.fromImage(img))
        # self.img_label.setPixmap(QtGui.QPixmap("/Users/bo/my/tmp/老夫子2/第1卷/1.jpg"))

        self.title = QLabel(self)
        self.title.setGeometry(220, 10, 100, 40)
        title_font = QtGui.QFont()
        title_font.setPointSize(16)
        title_font.setBold(True)
        title_font.setUnderline(True)
        self.title.setFont(title_font)
        self.title.setText(comic_info.title)
        self.title.setWordWrap(True)

        info_font = QtGui.QFont()
        info_font.setPointSize(14)
        # 作者
        self.author = QLabel(self)
        self.author.setText("作者 : " + comic_info.author)
        self.author.setGeometry(220, 50, 150, 40)
        self.author.setWordWrap(True)
        self.author.setFont(info_font)
        # 状态
        self.status = QLabel(self)
        self.status.setText("更新状态 : " + comic_info.status)
        self.status.setGeometry(220, 90, 150, 40)
        self.status.setFont(info_font)

        # 热度
        self.heat = QLabel(self)
        self.heat.setText("热度 : " + str(comic_info.heat))
        self.heat.setGeometry(220, 130, 150, 40)
        self.heat.setFont(info_font)

        # 类型
        self.tip = QLabel(self)
        self.tip.setText("类型 : " + comic_info.tip)
        self.tip.setGeometry(220, 170, 150, 40)
        self.tip.setWordWrap(True)
        self.tip.setFont(info_font)

        # web
        self.domain = QLabel(self)
        self.domain.setText(f"查看原网页 : {comic_info.domain}")
        self.domain.setText(f'查看原网页 : <a href="{comic_info.url}">{comic_info.domain}</a>')
        self.domain.setGeometry(220, 210, 150, 40)
        self.domain.setOpenExternalLinks(True)
        self.domain.setFont(info_font)

        # 描述
        self.describe = QLabel(self)
        self.describe.setText("  " + comic_info.describe)
        self.describe.setGeometry(10, 320, 350, 330)
        self.describe.setWordWrap(True)
        # 对齐方式
        self.describe.setAlignment(
            QtCore.Qt.AlignmentFlag.AlignLeading | QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignTop)

        # 章节列表,创建一个区域

        self.searchHBoxLayout = QHBoxLayout()
        # self.searchHBoxLayout.addSpacing()
        self.searchGroupBox = QGroupBox()
        self.searchGroupBox.setLayout(self.searchHBoxLayout)

        self.searchScroll = QScrollArea(self)
        self.searchScroll.setGeometry(370, 10, 574, 590)
        self.searchScroll.setWidget(self.searchGroupBox)
        self.searchScroll.setWidgetResizable(True)

        # 全选
        self.check_all = QCheckBox(self)
        self.check_all.setText("全选")
        self.check_all.setGeometry(700, 610, 100, 20)
        self.check_all.stateChanged.connect(self.check_all_fun)

        # 下载
        self.down_button = QPushButton(self)
        self.down_button.setText("下载")
        self.down_button.setGeometry(780, 605, 50, 30)

        self.down_button.clicked.connect(self.download_button_click)

        self.load_chapter_list_signa.connect(self.load_chapter)
        self.load_download_task_signa.connect(self.download_callback)

        # 调用对应的service的接口,获取章节列表
        constant.SERVICE.chapter(comic_info, self.load_chapter_list_signa.emit)

    i = 0
    searchVBoxLayout: QVBoxLayout
    check_box_list: List[QCheckBox] = []

    def check_all_fun(self):
        for check_box in self.check_box_list:
            check_box.setChecked(self.check_all.isChecked())

    def download_callback(self, task: DownloadTask):
        widget = DownLoadTaskWidget(task)
        self.down_v_box_layout.addWidget(widget)

    def download_button_click(self):
        flag = False
        for check_box in self.check_box_list:
            if check_box.isChecked():
                constant.SERVICE.parse_image(self.comic_info, check_box.property("chapter_info"),
                                             self.load_download_task_signa.emit)
                if not flag:
                    QMessageBox.information(self, "下载通知", "正在解析选中章节", QMessageBox.StandardButton.Yes)
                    flag = True

    def load_chapter(self, chapter_info: ChapterInfo):
        if self.i % 26 == 0:
            self.searchVBoxLayout = QVBoxLayout()
            self.searchVBoxLayout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)  # 对齐方式,研究了3个小时 o(╥﹏╥)o
            self.searchHBoxLayout.addLayout(self.searchVBoxLayout)

        check_box = QCheckBox()
        self.check_box_list.append(check_box)
        check_box.setText(chapter_info.title)
        check_box.setProperty("chapter_info", chapter_info)
        task = constant.downloaded_task_map.get(chapter_info.url)
        if task and task.status == -1:
            check_box.setStyleSheet('color:red')
            check_box.setChecked(True)

        self.searchVBoxLayout.addWidget(check_box)
        self.i += 1