Exemplo n.º 1
0
    def __init__(self, guiparent, giface, iclass_mapwin=None):
        self.giface = giface
        self.mapDisp = giface.GetMapDisplay()

        if iclass_mapwin:
            self.mapWin = iclass_mapwin
        else:
            self.mapWin = giface.GetMapWindow()

        self.guiparent = guiparent

        self.show_add_scatt_plot = False

        self.core = Core()

        self.cats_mgr = CategoriesManager(self, self.core)
        self.render_mgr = PlotsRenderingManager(scatt_mgr=self,
                                                cats_mgr=self.cats_mgr,
                                                core=self.core)

        self.thread = gThread()

        self.plots = {}

        self.plot_mode = None
        self.pol_sel_mode = [False, None]

        self.data_set = False

        self.cursorPlotMove = Signal("ScattsManager.cursorPlotMove")

        self.renderingStarted = self.render_mgr.renderingStarted
        self.renderingFinished = self.render_mgr.renderingFinished

        self.computingStarted = Signal("ScattsManager.computingStarted")

        if iclass_mapwin:
            self.digit_conn = IClassDigitConnection(self,
                                                    self.mapWin,
                                                    self.core.CatRastUpdater())
            self.iclass_conn = IClassConnection(self,
                                                iclass_mapwin.parent,
                                                self.cats_mgr)
        else:
            self.digit_conn = IMapWinDigitConnection()
            self.iclass_conn = IMapDispConnection(scatt_mgr=self,
                                                  cats_mgr=self.cats_mgr,
                                                  giface=self.giface)

        self._initSettings()

        self.modeSet = Signal("ScattsManager.mondeSet")
Exemplo n.º 2
0
class ScattsManager:
    """Main controller
    """

    def __init__(self, guiparent, giface, iclass_mapwin=None):
        self.giface = giface
        self.mapDisp = giface.GetMapDisplay()

        if iclass_mapwin:
            self.mapWin = iclass_mapwin
        else:
            self.mapWin = giface.GetMapWindow()

        self.guiparent = guiparent

        self.show_add_scatt_plot = False

        self.core = Core()

        self.cats_mgr = CategoriesManager(self, self.core)
        self.render_mgr = PlotsRenderingManager(scatt_mgr=self,
                                                cats_mgr=self.cats_mgr,
                                                core=self.core)

        self.thread = gThread()

        self.plots = {}

        self.plot_mode = None
        self.pol_sel_mode = [False, None]

        self.data_set = False

        self.cursorPlotMove = Signal("ScattsManager.cursorPlotMove")

        self.renderingStarted = self.render_mgr.renderingStarted
        self.renderingFinished = self.render_mgr.renderingFinished

        self.computingStarted = Signal("ScattsManager.computingStarted")

        if iclass_mapwin:
            self.digit_conn = IClassDigitConnection(self,
                                                    self.mapWin,
                                                    self.core.CatRastUpdater())
            self.iclass_conn = IClassConnection(self,
                                                iclass_mapwin.parent,
                                                self.cats_mgr)
        else:
            self.digit_conn = IMapWinDigitConnection()
            self.iclass_conn = IMapDispConnection(scatt_mgr=self,
                                                  cats_mgr=self.cats_mgr,
                                                  giface=self.giface)

        self._initSettings()

        self.modeSet = Signal("ScattsManager.mondeSet")

    def CleanUp(self):
        self.thread.Terminate()
        # there should be better way hot to clean up the thread
        # than calling the clean up function outside the thread,
        # which still may running
        self.core.CleanUp()

    def CleanUpDone(self):
        for scatt_id, scatt in self.plots.items():
            if scatt['scatt']:
                scatt['scatt'].CleanUp()

        self.plots.clear()

    def _initSettings(self):
        """Initialization of settings (if not already defined)
        """
        # initializes default settings
        initSettings = [
            ['selection', 'sel_pol', (255, 255, 0)],
            ['selection', 'sel_pol_vertex', (255, 0, 0)],
            ['selection', 'sel_area', (0, 255, 19)],
            ['selection', "snap_tresh", 10],
            ['selection', 'sel_area_opacty', 50],
            ['ellipses', 'show_ellips', True],
        ]

        for init in initSettings:
            UserSettings.ReadSettingsFile()
            UserSettings.Append(dict=UserSettings.userSettings,
                                group='scatt',
                                key=init[0],
                                subkey=init[1],
                                value=init[2],
                                overwrite=False)

    def SetData(self):
        self.iclass_conn.SetData()
        self.digit_conn.SetData()

    def SetBands(self, bands):
        self.busy = wx.BusyInfo(_("Loading data..."))
        self.data_set = False
        self.thread.Run(callable=self.core.CleanUp,
                        ondone=lambda event: self.CleanUpDone())

        if self.show_add_scatt_plot:
            show_add = True
        else:
            show_add = False

        self.all_bands_to_bands = dict(zip(bands, [-1] * len(bands)))
        self.all_bands = bands

        self.region = GetRegion()
        ncells = self.region["rows"] * self.region["cols"]

        if ncells > MAX_NCELLS:
            del self.busy
            self.data_set = True
            return

        self.bands = bands[:]
        self.bands_info = {}
        valid_bands = []

        for b in self.bands[:]:
            i = GetRasterInfo(b)

            self.bands_info[b] = i
            if i is not None:
                valid_bands.append(b)

        for i, b in enumerate(valid_bands):
            # name : index in core bands -
            # if not in core bands (not CELL type) -> index = -1
            self.all_bands_to_bands[b] = i

        self.thread.Run(callable=self.core.SetData,
                        bands=valid_bands,
                        ondone=self.SetDataDone,
                        userdata={"show_add": show_add})

    def SetDataDone(self, event):
        del self.busy
        self.data_set = True

        todo = event.ret
        self.bad_bands = event.ret
        bands = self.core.GetBands()

        self.bad_rasts = event.ret
        self.cats_mgr.SetData()
        if event.userdata['show_add']:
            self.AddScattPlot()

    def GetBands(self):
        return self.core.GetBands()

    def AddScattPlot(self):
        if not self.data_set and self.iclass_conn:
            self.show_add_scatt_plot = True
            self.iclass_conn.SetData()
            self.show_add_scatt_plot = False
            return
        if not self.data_set:
            GError(_('No data set.'))
            return

        self.computingStarted.emit()

        bands = self.core.GetBands()

        #added_bands_ids = []
        # for scatt_id in self.plots):
        #    added_bands_ids.append[idBandsToidScatt(scatt_id)]

        self.digit_conn.Update()

        ncells = self.region["rows"] * self.region["cols"]
        if ncells > MAX_NCELLS:
            GError(
                _(
                    parent=self.guiparent, mmessage=_(
                        "Interactive Scatter Plot Tool can not be used.\n"
                        "Number of cells (rows*cols) <%d> in current region"
                        "is higher than maximum limit <%d>.\n\n"
                        "You can reduce number of cells in current region using <g.region> command." %
                        (ncells, MAX_NCELLS))))
            return
        elif ncells > WARN_NCELLS:
            dlg = wx.MessageDialog(
                parent=self.guiparent,
                message=_("Number of cells (rows*cols) <%d> in current region is "
                          "higher than recommended threshold <%d>.\n"
                          "It is strongly advised to reduce number of cells "
                          "in current region below recommend threshold.\n "
                          "It can be done by <g.region> command.\n\n"
                          "Do you want to continue using "
                          "Interactive Scatter Plot Tool with this region?"
                          % (ncells, WARN_NCELLS)),
                style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_WARNING)
            ret = dlg.ShowModal()
            if ret != wx.ID_YES:
                return

        dlg = AddScattPlotDialog(parent=self.guiparent,
                                 bands=self.all_bands,
                                 check_bands_callback=self.CheckBands)

        if dlg.ShowModal() == wx.ID_OK:

            scatt_ids = []
            sel_bands = dlg.GetBands()

            for b_1, b_2 in sel_bands:
                transpose = False
                if b_1 > b_2:
                    transpose = True
                    tmp_band = b_2
                    b_2 = b_1
                    b_1 = tmp_band

                b_1_id = self.all_bands_to_bands[self.all_bands[b_1]]
                b_2_id = self.all_bands_to_bands[self.all_bands[b_2]]

                scatt_id = idBandsToidScatt(b_1_id, b_2_id, len(bands))
                if scatt_id in self.plots:
                    continue

                self.plots[scatt_id] = {'transpose': transpose,
                                        'scatt': None}
                scatt_ids.append(scatt_id)

            self._addScattPlot(scatt_ids)

        dlg.Destroy()

    def CheckBands(self, b_1, b_2):
        bands = self.core.GetBands()
        added_scatts_ids = self.plots.keys()

        b_1_id = self.all_bands_to_bands[self.all_bands[b_1]]
        b_2_id = self.all_bands_to_bands[self.all_bands[b_1]]

        scatt_id = idBandsToidScatt(b_1_id, b_2_id, len(bands))

        if scatt_id in added_scatts_ids:
            GWarning(
                parent=self.guiparent, message=_(
                    "Scatter plot with same band combination (regardless x y order) "
                    "is already displayed."))
            return False

        b_1_name = self.all_bands[b_1]
        b_2_name = self.all_bands[b_2]

        b_1_i = self.bands_info[b_1_name]
        b_2_i = self.bands_info[b_2_name]

        err = ""
        for b in [b_1_name, b_2_name]:
            if self.bands_info[b] is None:
                err += _("Band <%s> is not CELL (integer) type.\n" % b)
        if err:
            GMessage(parent=self.guiparent,
                     message=_("Scatter plot cannot be added.\n" + err))
            return False

        mrange = b_1_i['range'] * b_2_i['range']
        if mrange > MAX_SCATT_SIZE:
            GWarning(parent=self.guiparent,
                     message=_("Scatter plot cannot be added.\n"
                               "Multiple of bands ranges <%s:%d * %s:%d = %d> "
                               "is higher than maximum limit <%d>.\n"
                               % (b_1_name, b_1_i['range'], b_1_name, b_2_i['range'],
                                  mrange, MAX_SCATT_SIZE)))
            return False
        elif mrange > WARN_SCATT_SIZE:
            dlg = wx.MessageDialog(
                parent=self.guiparent,
                message=_(
                    "Multiple of bands ranges <%s:%d * %s:%d = %d> "
                    "is higher than recommended limit <%d>.\n"
                    "It is strongly advised to reduce range extend of bands"
                    "(e. g. using r.rescale) below recommended threshold.\n\n"
                    "Do you really want to add this scatter plot?" %
                    (b_1_name, b_1_i['range'],
                     b_1_name, b_2_i['range'],
                     mrange, WARN_SCATT_SIZE)),
                style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_WARNING)
            ret = dlg.ShowModal()
            if ret != wx.ID_YES:
                return False

        return True

    def _addScattPlot(self, scatt_ids):
        self.render_mgr.NewRunningProcess()
        self.thread.Run(callable=self.core.AddScattPlots,
                        scatt_ids=scatt_ids, ondone=self.AddScattPlotDone)

    def AddScattPlotDone(self, event):
        if not self.data_set:
            return

        scatt_ids = event.kwds['scatt_ids']
        for s_id in scatt_ids:
            trans = self.plots[s_id]['transpose']

            self.plots[s_id]['scatt'] = self.guiparent.NewScatterPlot(
                scatt_id=s_id, transpose=trans)

            self.plots[s_id]['scatt'].plotClosed.connect(self.PlotClosed)
            self.plots[s_id]['scatt'].cursorMove.connect(
                lambda x, y, scatt_id:
                self.cursorPlotMove.emit(x=x, y=y,
                                         scatt_id=scatt_id))

            if self.plot_mode:
                self.plots[s_id]['scatt'].SetMode(self.plot_mode)
                self.plots[s_id]['scatt'].ZoomToExtend()

        self.render_mgr.RunningProcessDone()

    def PlotClosed(self, scatt_id):
        del self.plots[scatt_id]

    def SetPlotsMode(self, mode):

        self.plot_mode = mode
        for scatt in six.itervalues(self.plots):
            if scatt['scatt']:
                scatt['scatt'].SetMode(mode)

        self.modeSet.emit(mode=mode)

    def ActivateSelectionPolygonMode(self, activate):
        self.pol_sel_mode[0] = activate
        for scatt in six.itervalues(self.plots):
            if not scatt['scatt']:
                continue
            scatt['scatt'].SetSelectionPolygonMode(activate)
            if not activate and self.plot_mode not in [
                    'zoom', 'pan', 'zoom_extend']:
                self.SetPlotsMode(None)

        self.render_mgr.RunningProcessDone()
        return activate

    def ProcessSelectionPolygons(self, process_mode):
        scatts_polygons = {}
        for scatt_id, scatt in six.iteritems(self.plots):
            if not scatt['scatt']:
                continue
            coords = scatt['scatt'].GetCoords()
            if coords is not None:
                scatts_polygons[scatt_id] = coords

        if not scatts_polygons:
            return

        value = 1
        if process_mode == 'remove':
            value = 0

        sel_cat_id = self.cats_mgr.GetSelectedCat()
        if not sel_cat_id:
            dlg = wx.MessageDialog(
                parent=self.guiparent,
                message=_(
                    "In order to select arrea in scatter plot, "
                    "you have to select class first.\n\n"
                    "There is no class yet, "
                    "do you want to create one?"),
                caption=_("No class selected"),
                style=wx.YES_NO)
            if dlg.ShowModal() == wx.ID_YES:
                self.iclass_conn.EmptyCategories()

        sel_cat_id = self.cats_mgr.GetSelectedCat()
        if not sel_cat_id:
            return

        for scatt in six.itervalues(self.plots):
            if scatt['scatt']:
                scatt['scatt'].SetEmpty()

        self.computingStarted.emit()

        self.render_mgr.NewRunningProcess()
        self.render_mgr.CategoryChanged(cat_ids=[sel_cat_id])
        self.render_mgr.CategoryCondsChanged(cat_ids=[sel_cat_id])

        self.thread.Run(callable=self.core.UpdateCategoryWithPolygons,
                        cat_id=sel_cat_id,
                        scatts_pols=scatts_polygons,
                        value=value, ondone=self.SetEditCatDataDone)

    def SetEditCatDataDone(self, event):
        if not self.data_set:
            return

        self.render_mgr.RunningProcessDone()
        if event.exception:
            GError(
                _("Error occurred during computation of scatter plot category:\n%s"),
                parent=self.guiparent,
                showTraceback=False)

        cat_id = event.ret
        self.iclass_conn.RenderCatRast(cat_id)

    def SettingsUpdated(self, chanaged_setts):
        self.render_mgr.RenderRequest()

        #['ellipses', 'show_ellips']
    def GetCategoriesManager(self):
        return self.cats_mgr