[GRASS-SVN] r57454 - sandbox/turek/scatter_plot
svn_grass at osgeo.org
svn_grass at osgeo.org
Thu Aug 15 12:16:05 PDT 2013
Author: turek
Date: 2013-08-15 12:16:04 -0700 (Thu, 15 Aug 2013)
New Revision: 57454
Modified:
sandbox/turek/scatter_plot/testing_patch.diff
Log:
backend clean up and added comments
Modified: sandbox/turek/scatter_plot/testing_patch.diff
===================================================================
--- sandbox/turek/scatter_plot/testing_patch.diff 2013-08-13 21:48:39 UTC (rev 57453)
+++ sandbox/turek/scatter_plot/testing_patch.diff 2013-08-15 19:16:04 UTC (rev 57454)
@@ -1,6 +1,6 @@
Index: include/defs/vedit.h
===================================================================
---- include/defs/vedit.h (revision 57437)
+--- include/defs/vedit.h (revision 57453)
+++ include/defs/vedit.h (working copy)
@@ -33,6 +33,8 @@
int Vedit_merge_lines(struct Map_info *, struct ilist *);
@@ -13,36 +13,37 @@
Index: include/defs/imagery.h
===================================================================
---- include/defs/imagery.h (revision 57437)
+--- include/defs/imagery.h (revision 57453)
+++ include/defs/imagery.h (working copy)
-@@ -110,6 +110,22 @@
+@@ -110,6 +110,23 @@
FILE *I_fopen_subgroup_ref_new(const char *, const char *);
FILE *I_fopen_subgroup_ref_old(const char *, const char *);
+/* scatt_plt.c */
+void I_sc_init_cats(struct scCats *, int, int);
+void I_sc_free_cats(struct scCats *);
-+int I_sc_add_cat(struct scCats *, int);
++int I_sc_add_cat(struct scCats *);
+int I_sc_insert_scatt_data(struct scCats *, struct scdScattData *, int, int);
+
-+void I_scd_init_scatt_data(struct scdScattData *, int, int, void *, struct Range, struct Range);
-+void I_scd_free_scatt_data(struct scdScattData *);
++void I_scd_init_scatt_data(struct scdScattData *, int, int, void *);
+
+int I_compute_scatts(struct Cell_head *, struct scCats *, const char **,
-+ int, const char **, struct scCats *, const char **);
++ const char **, int, struct scCats *, const char **);
+
+int I_create_cat_rast(struct Cell_head *, const char *);
+int I_insert_patch_to_cat_rast(const char *, struct Cell_head *, const char *);
+
++int I_id_scatt_to_bands(const int, const int, int *, int *);
++int I_bands_to_id_scatt(const int, const int, const int, int *);
+
/* sig.c */
int I_init_signatures(struct Signature *, int);
int I_new_signature(struct Signature *);
Index: include/imagery.h
===================================================================
---- include/imagery.h (revision 57437)
+--- include/imagery.h (revision 57453)
+++ include/imagery.h (working copy)
-@@ -135,6 +135,59 @@
+@@ -135,6 +135,55 @@
} IClass_statistics;
@@ -57,16 +58,16 @@
+*/
+struct scCats
+{
-+ int type; /*!< SC_SCATT_DATA -> computed scatter plots, SC_SCATT_CONDITIONS -> set conditions for scatter plots*/
++ int type; /*!< SC_SCATT_DATA -> computed scatter plots, SC_SCATT_CONDITIONS -> set conditions for scatter plots to be computed*/
+
-+ int n_cats; /*!< number of alocated categories */
++ int n_cats; /*!< number of alocated categories */
+
-+ int n_bands; /*!< number of analyzed bands */
-+ int n_scatts; /*!< number of possible scattter plot which can be created from bands */
++ int n_bands; /*!< number of analyzed bands */
++ int n_scatts; /*!< number of possible scattter plot which can be created from bands */
+
-+ int n_a_cats; /*!< number of used categories */
-+ int * cats_ids; /*!< category id */
-+ int * cats_idxs; /*!< internal category idx (idx in cats_arr)*/
++ int n_a_cats; /*!< number of used/active categories */
++ int * cats_ids; /*!< (cat_idx->cat_id) array index is internal idx (position in cats_arr) and id is saved in it's position*/
++ int * cats_idxs; /*!< (cat_id->cat_idx) array index is id and internal idx is saved in it's position*/
+
+ struct scScatts ** cats_arr; /*!< array of pointers to struct scScatts */
+};
@@ -76,11 +77,11 @@
+*/
+struct scScatts
+{
-+ int n_a_scatts; /*!< number of used scatter plots */
++ int n_a_scatts; /*!< number of used/active scatter plots*/
+
+ int * scatts_bands; /*!< array of bands for which represents the scatter plots,
-+ size of scatts_bands is two times bigger than size of scatts_arr (every scatter plot has assigned two bands)*/
-+ int * scatt_idxs; /*!< internal idx of the scatter plot (idx in scatts_arr)*/
++ every scatter plot has assigned two bads (size of array is n_a_scatts * 2)*/
++ int * scatt_idxs; /*!< (scatt_id->scatt_idx) internal idx of the scatter plot (position in scatts_arr)*/
+
+ struct scdScattData ** scatts_arr; /*!< array of pointers to scdScattData */
+};
@@ -90,1310 +91,19 @@
+struct scdScattData
+{
+ int n_vals; /* Number of values in scatter plot. */
-+
-+ struct Range band_1_range; /* Range of band 1 (min and max), TODO range attributes could be moved to scCats */
-+ struct Range band_2_range; /* Range of band 2 (min and max) */
+
-+
-+ unsigned char * b_conds_arr; /* array of selected areas (used for SC_SCATT_CONDITIONS type) */
-+ unsigned int * scatt_vals_arr; /* array of computed areas (used for SC_SCATT_DATA type) */
++ unsigned char * b_conds_arr; /* array of selected areas (used for SC_SCATT_CONDITIONS type) otherwise NULL */
++ unsigned int * scatt_vals_arr; /* array of computed areas (used for SC_SCATT_DATA type) otherwise NULL */
+};
+
#define SIGNATURE_TYPE_MIXED 1
#define GROUPFILE "CURGROUP"
-Index: gui/wxpython/iclass/dialogs.py
-===================================================================
---- gui/wxpython/iclass/dialogs.py (revision 57437)
-+++ gui/wxpython/iclass/dialogs.py (working copy)
-@@ -333,13 +333,19 @@
- toolbar.SetCategories(catNames = catNames, catIdx = cats)
- if name in catNames:
- toolbar.choice.SetStringSelection(name)
-+ cat = toolbar.GetSelectedCategoryIdx()
- elif catNames:
- toolbar.choice.SetSelection(0)
--
-+ cat = toolbar.GetSelectedCategoryIdx()
-+ else:
-+ cat = None
-+
- if toolbar.choice.IsEmpty():
- toolbar.EnableControls(False)
- else:
- toolbar.EnableControls(True)
-+
-+ self.mapWindow.CategoryChanged(cat)
- # don't forget to update maps, histo, ...
-
- def GetSelectedIndices(self, state = wx.LIST_STATE_SELECTED):
-Index: gui/wxpython/iclass/toolbars.py
-===================================================================
---- gui/wxpython/iclass/toolbars.py (revision 57437)
-+++ gui/wxpython/iclass/toolbars.py (working copy)
-@@ -46,9 +46,7 @@
- 'importAreas' : MetaIcon(img = 'layer-import',
- label = _('Import training areas from vector map')),
- 'addRgb' : MetaIcon(img = 'layer-rgb-add',
-- label = _('Add RGB map layer')),
-- 'scatt_plot' : MetaIcon(img = 'layer-raster-analyze',
-- label = _('Open Scatter Plot Tool (EXPERIMENTAL GSoC 2013)')),
-+ label = _('Add RGB map layer'))
- }
-
- class IClassMapToolbar(BaseToolbar):
-@@ -117,10 +115,7 @@
- ("zoomBack", icons["zoomBack"],
- self.parent.OnZoomBack),
- ("zoomToMap", icons["zoomExtent"],
-- self.parent.OnZoomToMap),
-- (None, ),
-- ("scatt_plot", iClassIcons["scatt_plot"],
-- self.parent.OnScatterplot)
-+ self.parent.OnZoomToMap)
- ))
- class IClassToolbar(BaseToolbar):
- """!IClass toolbar
-@@ -156,7 +151,7 @@
- """!Toolbar data"""
- icons = iClassIcons
- return self._getToolbarData((("selectGroup", icons['selectGroup'],
-- self.parent.OnAddBands),
-+ lambda event : self.parent.AddBands()),
- (None, ),
- ("classManager", icons['classManager'],
- self.parent.OnCategoryManager),
-Index: gui/wxpython/iclass/frame.py
-===================================================================
---- gui/wxpython/iclass/frame.py (revision 57437)
-+++ gui/wxpython/iclass/frame.py (working copy)
-@@ -65,6 +65,8 @@
- IClassExportAreasDialog, IClassMapDialog
- from iclass.plots import PlotPanel
-
-+from grass.pydispatch.signal import Signal
-+
- class IClassMapFrame(DoubleMapFrame):
- """! wxIClass main frame
-
-@@ -115,6 +117,10 @@
- lambda:
- self.statusbarManager.statusbarItems['coordinates'].SetAdditionalInfo(None))
- self.SetSize(size)
-+
-+ self.groupSet = Signal("IClassMapFrame.groupSet")
-+ self.categoryChanged = Signal('IClassMapFrame.categoryChanged')
-+
- #
- # Add toolbars
- #
-@@ -178,7 +184,7 @@
- self.dialogs['category'] = None
-
- # PyPlot init
-- self.plotPanel = PlotPanel(self, stats_data = self.stats_data)
-+ self.plotPanel = PlotPanel(self, giface = self._giface, stats_data = self.stats_data)
-
- self._addPanes()
- self._mgr.Update()
-@@ -231,7 +237,30 @@
- return False
-
- return vectorName
--
-+
-+ def OnScatterplot(self, event):
-+ """!Init interactive scatterplot tools
-+ """
-+ if self.dialogs['scatt_plot']:
-+ self.dialogs['scatt_plot'].Raise()
-+ return
-+
-+ try:
-+ from scatt_plot.dialogs import ScattPlotMainDialog
-+ self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface, iclass_mapwin = self.GetFirstWindow())
-+
-+ scatt_mgr = self.dialogs['scatt_plot'].GetScattMgr()
-+ scatt_mgr.DigitDataChanged(self.toolbars['vdigit'].mapLayer.GetName(), self.GetFirstWindow().digit)
-+
-+ self.dialogs['scatt_plot'].CenterOnScreen()
-+ self.dialogs['scatt_plot'].Show()
-+
-+ except ImportError as e:
-+ GError(parent = self, showTraceback = False, message = _("The Scatter Plot Tool is not installed:\n%s" % str(e)))
-+ except Exception as e:
-+ GError(parent = self, message = _("Unable to launch the Scatter Plot Tool:\n%s" % str(e)))
-+ return
-+
- def RemoveTempVector(self):
- """!Removes temporary vector map with training areas"""
- ret = RunCommand(prog = 'g.remove',
-@@ -471,7 +500,7 @@
-
- self.Render(self.GetFirstWindow())
-
-- def OnAddBands(self, event):
-+ def AddBands(self):
- """!Add imagery group"""
- dlg = IClassGroupDialog(self, group = self.group)
- if dlg.ShowModal() == wx.ID_OK:
-@@ -482,7 +511,8 @@
- """!Set imagery group"""
- group = grass.find_file(name = name, element = 'group')
- if group['name']:
-- self.group = group['name']
-+ self.group = group['name']
-+ self.groupSet.emit(group = group['name'])
- else:
- GError(_("Group <%s> not found") % name, parent = self)
-
-@@ -783,17 +813,20 @@
-
- Updates number of stddev, histograms, layer in preview display.
- """
-- stat = self.stats_data.GetStatistics(currentCat)
-- nstd = stat.nstd
-- self.toolbars['iClass'].UpdateStddev(nstd)
--
-- self.plotPanel.UpdateCategory(currentCat)
-- self.plotPanel.OnPlotTypeSelected(None)
-+ if currentCat:
-+ stat = self.stats_data.GetStatistics(currentCat)
-+ nstd = stat.nstd
-+ self.toolbars['iClass'].UpdateStddev(nstd)
-+
-+ self.plotPanel.UpdateCategory(currentCat)
-+ self.plotPanel.OnPlotTypeSelected(None)
-
-- name = stat.rasterName
-- name = self.previewMapManager.GetAlias(name)
-- if name:
-- self.previewMapManager.SelectLayer(name)
-+ name = stat.rasterName
-+ name = self.previewMapManager.GetAlias(name)
-+ if name:
-+ self.previewMapManager.SelectLayer(name)
-+
-+ self.categoryChanged.emit(cat = currentCat)
-
- def DeleteAreas(self, cats):
- """!Removes all training areas of given categories
-@@ -1120,27 +1153,6 @@
-
- self.GetFirstWindow().mouse['use'] = 'pointer'
-
-- def OnScatterplot(self, event):
-- """!Init interactive scatterplot tools
-- """
-- if self.dialogs['scatt_plot']:
-- self.dialogs['scatt_plot'].Raise()
-- return
--
-- try:
-- from scatt_plot.dialogs import ScattPlotMainDialog
-- except:
-- GError(parent = self, message = _("The Scatter Plot Tool is not installed."))
-- return
--
-- self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface, iclass_mapwin = self.GetFirstWindow())
--
-- scatt_mgr = self.dialogs['scatt_plot'].GetScattMgr()
-- scatt_mgr.DigitDataChanged(self.toolbars['vdigit'].mapLayer.GetName(), self.GetFirstWindow().digit)
--
-- self.dialogs['scatt_plot'].CenterOnScreen()
-- self.dialogs['scatt_plot'].Show()
--
- class MapManager:
- """! Class for managing map renderer.
-
-Index: gui/wxpython/iclass/plots.py
-===================================================================
---- gui/wxpython/iclass/plots.py (revision 57437)
-+++ gui/wxpython/iclass/plots.py (working copy)
-@@ -28,7 +28,7 @@
- for each band and for one category. Coincidence plots show min max range
- of classes for each band.
- """
-- def __init__(self, parent, stats_data):
-+ def __init__(self, parent, giface, stats_data):
- scrolled.ScrolledPanel.__init__(self, parent)
-
- self.SetupScrolling(scroll_x = False, scroll_y = True)
-@@ -38,26 +38,62 @@
- self.stats_data = stats_data
- self.currentCat = None
-
-+ self._giface = giface
-+
- self.mainSizer = wx.BoxSizer(wx.VERTICAL)
--
-+
- self._createControlPanel()
--
-+ self._createPlotPanel()
-+ self._createScatterPlotPanel()
-+
- self.SetSizer(self.mainSizer)
- self.mainSizer.Fit(self)
- self.Layout()
-
-+ def _createPlotPanel(self):
-+
-+ self.canvasPanel = wx.Panel(parent=self)
-+ self.mainSizer.Add(item = self.canvasPanel, proportion = 1, flag = wx.EXPAND, border = 0)
-+ self.canvasSizer = wx.BoxSizer(wx.VERTICAL)
-+ self.canvasPanel.SetSizer(self.canvasSizer)
-+
- def _createControlPanel(self):
- self.plotSwitch = wx.Choice(self, id = wx.ID_ANY,
- choices = [_("Histograms"),
-- _("Coincident plots")])
-+ _("Coincident plots"),
-+ _("Scatter plots")])
- self.mainSizer.Add(self.plotSwitch, proportion = 0, flag = wx.EXPAND|wx.ALL, border = 5)
- self.plotSwitch.Bind(wx.EVT_CHOICE, self.OnPlotTypeSelected)
--
-+
-+ def _createScatterPlotPanel(self):
-+ """!Init interactive scatterplot tools
-+ """
-+ try:
-+ from scatt_plot.dialogs_iclass import IClassScatterPlotsPanel
-+ self.scatt_plot_panel = IClassScatterPlotsPanel(parent=self, giface=self._giface, iclass_mapwin = self.parent.GetFirstWindow())
-+ self.mainSizer.Add(self.scatt_plot_panel, proportion = 1, flag = wx.EXPAND, border = 0)
-+ self.scatt_plot_panel.Hide()
-+ except ImportError as e:
-+ self.scatt_plot_panel = None
-+
- def OnPlotTypeSelected(self, event):
- """!Plot type selected"""
-+
-+ if self.plotSwitch.GetSelection() in [0, 1]:
-+ self.SetupScrolling(scroll_x = False, scroll_y = True)
-+ self.scatt_plot_panel.Hide()
-+ self.canvasPanel.Show()
-+ self.Layout()
-+
-+ elif self.plotSwitch.GetSelection() == 2:
-+ self.SetupScrolling(scroll_x = False, scroll_y = False)
-+ self.scatt_plot_panel.Show()
-+ self.canvasPanel.Hide()
-+ self.Layout()
-+
- if self.currentCat is None:
- return
--
-+
- if self.plotSwitch.GetSelection() == 0:
- stat = self.stats_data.GetStatistics(self.currentCat)
- if not stat.IsReady():
-@@ -66,7 +102,10 @@
- self.DrawHistograms(stat)
- else:
- self.DrawCoincidencePlots()
--
-+
-+ self.Layout()
-+
-+
- def StddevChanged(self):
- """!Standard deviation multiplier changed, redraw histograms"""
- if self.plotSwitch.GetSelection() == 0:
-@@ -89,7 +128,7 @@
- panel.Destroy()
-
- self.canvasList = []
--
-+
- def ClearPlots(self):
- """!Clears plot canvases"""
- for bandIdx in range(len(self.bandList)):
-@@ -104,15 +143,15 @@
- def CreatePlotCanvases(self):
- """!Create plot canvases according to the number of bands"""
- for band in self.bandList:
-- canvas = plot.PlotCanvas(self)
-+ canvas = plot.PlotCanvas(self.canvasPanel)
- canvas.SetMinSize((-1, 140))
- canvas.SetFontSizeTitle(10)
- canvas.SetFontSizeAxis(8)
- self.canvasList.append(canvas)
-
-- self.mainSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
--
-- self.SetVirtualSize(self.GetBestVirtualSize())
-+ self.canvasSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
-+
-+ self.SetVirtualSize(self.GetBestVirtualSize())
- self.Layout()
-
- def UpdatePlots(self, group, currentCat, stats_data):
-@@ -138,7 +177,7 @@
-
- def UpdateCategory(self, cat):
- self.currentCat = cat
--
-+
- def DrawCoincidencePlots(self):
- """!Draw coincidence plots"""
- for bandIdx in range(len(self.bandList)):
-Index: gui/wxpython/scatt_plot/gthreading.py
-===================================================================
---- gui/wxpython/scatt_plot/gthreading.py (revision 0)
-+++ gui/wxpython/scatt_plot/gthreading.py (working copy)
-@@ -0,0 +1,134 @@
-+"""!
-+ at package scatt_plot.gthreading
-+
-+Classes:
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+
-+import os
-+import sys
-+import time
-+import threading
-+import Queue
-+
-+import wx
-+from core.gconsole import wxCmdRun, wxCmdDone, wxCmdPrepare
-+
-+class gThread(threading.Thread):
-+ """!Thread for GRASS commands"""
-+ requestId = 0
-+
-+ def __init__(self, receiver, requestQ=None, resultQ=None, **kwds):
-+ """!
-+ @param receiver event receiver (used in PostEvent)
-+ """
-+ threading.Thread.__init__(self, **kwds)
-+
-+ if requestQ is None:
-+ self.requestQ = Queue.Queue()
-+ else:
-+ self.requestQ = requestQ
-+
-+ if resultQ is None:
-+ self.resultQ = Queue.Queue()
-+ else:
-+ self.resultQ = resultQ
-+
-+ self.setDaemon(True)
-+
-+ self.receiver = receiver
-+ self._want_abort_all = False
-+
-+ self.start()
-+
-+ def Run(self, *args, **kwds):
-+ """!Run command in queue
-+
-+ @param args unnamed command arguments
-+ @param kwds named command arguments
-+
-+ @return request id in queue
-+ """
-+ gThread.requestId += 1
-+ self.requestQ.put((gThread.requestId, args, kwds))
-+
-+ return gThread.requestId
-+
-+ def GetId(self):
-+ """!Get id for next command"""
-+ return gThread.requestId + 1
-+
-+ def SetId(self, id):
-+ """!Set starting id"""
-+ gThread.requestId = id
-+
-+ def run(self):
-+ os.environ['GRASS_MESSAGE_FORMAT'] = 'gui'
-+ while True:
-+ requestId, args, kwds = self.requestQ.get()
-+ for key in ('callable', 'onDone', 'onPrepare', 'userData'):
-+ if key in kwds:
-+ vars()[key] = kwds[key]
-+ del kwds[key]
-+ else:
-+ vars()[key] = None
-+
-+ requestTime = time.time()
-+
-+ #if self._want_abort_all and self.requestCmd is not None:
-+ # self.requestCmd.abort()
-+ # if self.requestQ.empty():
-+ # self._want_abort_all = False
-+
-+ # prepare
-+ if self.receiver:
-+ event = wxCmdPrepare(type = 'method',
-+ time=requestTime,
-+ pid=requestId)
-+
-+ wx.PostEvent(self.receiver, event)
-+
-+ # run command
-+ event = wxCmdRun(type = 'method',
-+ pid=requestId)
-+
-+ wx.PostEvent(self.receiver, event)
-+
-+ time.sleep(.1)
-+
-+ ret = None
-+ exception = None
-+
-+ #to
-+ #try:
-+ ret = vars()['callable'](*args, **kwds)
-+ #except Exception as e:
-+ # exception = e;
-+
-+ self.resultQ.put((requestId, ret))
-+
-+ time.sleep(.1)
-+
-+ if self.receiver:
-+ event = wxCmdDone(type = 'cmd',
-+ kwds = kwds,
-+ args = args, #TODO expand args to kwds
-+ ret=ret,
-+ exception=exception,
-+ pid=requestId)
-+
-+ # send event
-+ wx.PostEvent(self.receiver, event)
-+
-+ def abort(self, abortall=True):
-+ """!Abort command(s)"""
-+ if abortall:
-+ self._want_abort_all = True
-+ if self.requestQ.empty():
-+ self._want_abort_all = False
-\ No newline at end of file
-Index: gui/wxpython/scatt_plot/dialogs_iclass.py
-===================================================================
---- gui/wxpython/scatt_plot/dialogs_iclass.py (revision 0)
-+++ gui/wxpython/scatt_plot/dialogs_iclass.py (working copy)
-@@ -0,0 +1,436 @@
-+"""!
-+ at package scatt_plot.dialogs
-+
-+ at brief GUI.
-+
-+Classes:
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+import os
-+import sys
-+
-+import wx
-+import wx.lib.scrolledpanel as scrolled
-+import wx.lib.mixins.listctrl as listmix
-+import wx.lib.flatnotebook as FN
-+import wx.aui
-+
-+from core import globalvar
-+from core.gcmd import GException, GError, RunCommand
-+
-+from gui_core.gselect import Select
-+
-+from scatt_plot.controllers import ScattsManager
-+from scatt_plot.toolbars_iclass import MainToolbar
-+from scatt_plot.sc_pl_core import idScattToidBands
-+from scatt_plot.plots import ScatterPlotWidget
-+
-+try:
-+ from agw import aui
-+except ImportError:
-+ import wx.lib.agw.aui as aui
-+
-+class IClassScatterPlotsPanel(wx.Panel):
-+ def __init__(self, parent, giface, iclass_mapwin = None,
-+ id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-+
-+ #wx.SplitterWindow.__init__(self, parent = parent, id = id,
-+ # style = wx.SP_LIVE_UPDATE)
-+ wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
-+
-+ #self.head_panel = wx.Panel(parent = self, id = wx.ID_ANY)
-+ self.scatt_mgr = ScattsManager(guiparent = self, giface = giface, iclass_mapwin = iclass_mapwin)
-+
-+ # toobars
-+ self.toolbars = {}
-+ self.toolbars['mainToolbar'] = MainToolbar(parent = self, scatt_mgr = self.scatt_mgr)
-+ self._createCategoryPanel(self)
-+
-+ self.plot_panel = IClassPlotPanel(self, self.scatt_mgr)
-+
-+ mainsizer = wx.BoxSizer(wx.VERTICAL)
-+ mainsizer.Add(item = self.toolbars['mainToolbar'], proportion = 0, flag = wx.EXPAND)
-+ mainsizer.Add(item = self.catsPanel, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT , border = 5)
-+ mainsizer.Add(item = self.plot_panel, proportion = 1, flag = wx.EXPAND)
-+ self.catsPanel.Hide()
-+ self.SetSizer(mainsizer)
-+
-+
-+ #self.SetSashGravity(0.5)
-+ #self.SplitHorizontally(self.head_panel, self.plot_panel, -50)
-+ self.Layout()
-+ #self.SetAutoLayout(1)
-+
-+ def NewScatterPlot(self, scatt_id):
-+ return self.plot_panel.NewScatterPlot(scatt_id)
-+
-+ def ShowCategoryPanel(self, show):
-+ self.catsPanel.Show(show)
-+
-+ #if show:
-+ # self.SetSashSize(5)
-+ #else:
-+ # self.SetSashSize(0)
-+ self.plot_panel.SetVirtualSize(self.plot_panel.GetBestVirtualSize())
-+ self.Layout()
-+
-+ def _createCategoryPanel(self, parent):
-+ self.catsPanel = wx.Panel(parent = parent)
-+ self.cats_list = CategoryListCtrl(parent = self.catsPanel,
-+ cats_mgr = self.scatt_mgr.GetCategoriesManager())
-+
-+ self.catsPanel.SetMaxSize((-1, 150))
-+
-+ box_capt = wx.StaticBox(parent = self.catsPanel, id = wx.ID_ANY,
-+ label = ' %s ' % _("Classes manager for scatter plots"))
-+ catsSizer = wx.StaticBoxSizer(box_capt, wx.VERTICAL)
-+
-+ catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND | wx.ALL)
-+ self.catsPanel.SetSizer(catsSizer)
-+
-+
-+class IClassPlotPanel(scrolled.ScrolledPanel):
-+ def __init__(self, parent, scatt_mgr, id = wx.ID_ANY):
-+
-+ scrolled.ScrolledPanel.__init__(self, parent)
-+ self.SetupScrolling(scroll_x = False, scroll_y = True)
-+
-+ self.scatt_mgr = scatt_mgr
-+
-+ self.mainPanel = wx.Panel(parent = self, id = wx.ID_ANY)
-+
-+ #self._createCategoryPanel()
-+ # Fancy gui
-+ self._mgr = aui.AuiManager(self.mainPanel)
-+ #self._mgr.SetManagedWindow(self)
-+
-+ self._mgr.Update()
-+
-+ self._doLayout()
-+ self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
-+
-+ dlgSize = (-1, 400)
-+ #self.SetBestSize(dlgSize)
-+ #self.SetInitialSize(dlgSize)
-+ self.SetAutoLayout(1)
-+ #fix goutput's pane size (required for Mac OSX)
-+ #if self.gwindow:
-+ # self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
-+
-+ def OnScroll(self, event):
-+ event.Skip()
-+ wx.CallAfter(self._mgr.Update)
-+ wx.CallAfter(self.Layout)
-+
-+ def _doLayout(self):
-+
-+ mainsizer = wx.BoxSizer(wx.VERTICAL)
-+ mainsizer.Add(item = self.mainPanel, proportion = 1, flag = wx.EXPAND)
-+ self.SetSizer(mainsizer)
-+
-+ self.Layout()
-+ self.SetupScrolling()
-+
-+ def OnCloseDialog(self, event):
-+ """!Close dialog"""
-+ self.scatt_mgr.CleanUp()
-+ self.Destroy()
-+
-+ def OnSettings(self, event):
-+ pass
-+
-+ def NewScatterPlot(self, scatt_id):
-+ #TODO needs to be resolved (should be in this class)
-+
-+ scatt = ScatterPlotWidget(parent = self.mainPanel,
-+ scatt_mgr = self.scatt_mgr,
-+ scatt_id = scatt_id)
-+
-+ bands = self.scatt_mgr.GetBands()
-+ #TODO too low level
-+ b1_id, b2_id = idScattToidBands(scatt_id, len(bands))
-+
-+ self._mgr.AddPane(scatt,
-+ aui.AuiPaneInfo().Dockable(True).Floatable(True).
-+ Name("scatter plot %d" % scatt_id).MinSize((-1, 300)).Caption(("%s x: %s y: %s") % (_("scatter plot"), bands[b1_id], bands[b2_id])).
-+ Center().Position(1).MaximizeButton(True).
-+ MinimizeButton(True).CaptionVisible(True).
-+ CloseButton(True).Layer(0))
-+ self._mgr.Update()
-+
-+ self.SetVirtualSize(self.GetBestVirtualSize())
-+ self.Layout()
-+
-+ return scatt
-+
-+ def GetScattMgr(self):
-+ return self.scatt_mgr
-+
-+class CategoryListCtrl(wx.ListCtrl,
-+ listmix.ListCtrlAutoWidthMixin,
-+ listmix.TextEditMixin):
-+
-+ def __init__(self, parent, cats_mgr, id = wx.ID_ANY):
-+
-+ wx.ListCtrl.__init__(self, parent, id,
-+ style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES)
-+ self.columns = ((_('Class name'), 'name'),
-+ (_('Color'), 'color'))
-+ self.Populate(columns = self.columns)
-+
-+ self.cats_mgr = cats_mgr
-+ self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+
-+ self.rightClickedItemIdx = wx.NOT_FOUND
-+
-+ listmix.ListCtrlAutoWidthMixin.__init__(self)
-+
-+ listmix.TextEditMixin.__init__(self)
-+
-+ self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnEdit)
-+ self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSel)
-+
-+ self.cats_mgr.setCategoryAttrs.connect(self.Update)
-+ self.cats_mgr.deletedCategory.connect(self.Update)
-+ self.cats_mgr.addedCategory.connect(self.Update)
-+
-+ def Update(self, **kwargs):
-+ self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+ self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
-+
-+ def InitCoreCats(self):
-+ self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+ self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
-+
-+ def SetVirtualData(self, row, column, text):
-+ attr = self.columns[column][1]
-+ if attr == 'name':
-+ try:
-+ text.encode('ascii')
-+ except UnicodeEncodeError:
-+ GMessage(parent = self, message = _("Please use only ASCII characters."))
-+ return
-+
-+ cat_id = self.cats_mgr.GetCategories()[row]
-+
-+ self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
-+ self.cats_mgr.SetCategoryAttrs(cat_id, {attr : text})
-+ self.cats_mgr.setCategoryAttrs.connect(self.Update)
-+
-+ self.Select(row)
-+
-+ def Populate(self, columns):
-+ for i, col in enumerate(columns):
-+ self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
-+
-+ self.SetColumnWidth(0, 100)
-+ self.SetColumnWidth(1, 100)
-+
-+ def AddCategory(self):
-+
-+ self.cats_mgr.addedCategory.disconnect(self.Update)
-+ cat_id = self.cats_mgr.AddCategory()
-+ self.cats_mgr.addedCategory.connect(self.Update)
-+
-+ if cat_id < 0:
-+ GError(_("Maximum limit of categories number was reached."))
-+ return
-+ self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+
-+ def DeleteCategory(self):
-+ indexList = sorted(self.GetSelectedIndices(), reverse = True)
-+ cats = []
-+ for i in indexList:
-+ # remove temporary raster
-+ cat_id = self.cats_mgr.GetCategories()[i]
-+
-+ cats.append(cat_id)
-+
-+ self.cats_mgr.deletedCategory.disconnect(self.Update)
-+ self.cats_mgr.DeleteCategory(cat_id)
-+ self.cats_mgr.deletedCategory.connect(self.Update)
-+
-+ self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+
-+ def OnSel(self, event):
-+ event.Skip()
-+
-+ def GetSelectedIndices(self, state = wx.LIST_STATE_SELECTED):
-+ indices = []
-+ lastFound = -1
-+ while True:
-+ index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state)
-+ if index == -1:
-+ break
-+ else:
-+ lastFound = index
-+ indices.append(index)
-+ return indices
-+
-+ def OnEdit(self, event):
-+ currentItem = event.m_itemIndex
-+ currentCol = event.m_col
-+
-+ if currentCol == 1:
-+ dlg = wx.ColourDialog(self)
-+ dlg.GetColourData().SetChooseFull(True)
-+
-+ if dlg.ShowModal() == wx.ID_OK:
-+ color = dlg.GetColourData().GetColour().Get()
-+ color = ':'.join(map(str, color))
-+ self.SetVirtualData(currentItem, currentCol, color)
-+ dlg.Destroy()
-+ wx.CallAfter(self.SetFocus)
-+
-+ event.Skip()
-+
-+
-+ def DeselectAll(self):
-+ """!Deselect all items"""
-+ indexList = self.GetSelectedIndices()
-+ for i in indexList:
-+ self.Select(i, on = 0)
-+
-+ # no highlight
-+ self.OnCategorySelected(None)
-+
-+ def OnGetItemText(self, item, col):
-+ attr = self.columns[col][1]
-+ cat_id = self.cats_mgr.GetCategories()[item]
-+
-+ return self.cats_mgr.GetCategoryAttrs(cat_id)[attr]
-+
-+ def OnGetItemImage(self, item):
-+ return -1
-+
-+ def OnGetItemAttr(self, item):
-+ return None
-+
-+class AddScattPlotDialog(wx.Dialog):
-+
-+ def __init__(self, parent, bands, id = wx.ID_ANY):
-+
-+ wx.Dialog.__init__(self, parent, title = ("Add scatter plot"), id = id)
-+
-+ self.bands = bands
-+
-+ self.scatt_id = None
-+
-+ self._createWidgets()
-+
-+ def _createWidgets(self):
-+
-+ self.labels = {}
-+ self.params = {}
-+
-+ self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
-+
-+ self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+ choices = self.bands,
-+ style = wx.CB_READONLY, size = (350, 30))
-+
-+ self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 2:"))
-+
-+ self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+ choices = self.bands,
-+ style = wx.CB_READONLY, size = (350, 30))
-+
-+ # buttons
-+ self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
-+
-+ self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
-+
-+ self._layout()
-+
-+ def _layout(self):
-+
-+ border = wx.BoxSizer(wx.VERTICAL)
-+ dialogSizer = wx.BoxSizer(wx.VERTICAL)
-+
-+ regionSizer = wx.BoxSizer(wx.HORIZONTAL)
-+
-+ dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label,
-+ sel = self.band_1_ch))
-+
-+ dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label,
-+ sel = self.band_2_ch))
-+
-+ # buttons
-+ self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
-+
-+ self.btnsizer.Add(item = self.btn_close, proportion = 0,
-+ flag = wx.ALL | wx.ALIGN_CENTER,
-+ border = 10)
-+
-+ self.btnsizer.Add(item = self.btn_ok, proportion = 0,
-+ flag = wx.ALL | wx.ALIGN_CENTER,
-+ border = 10)
-+
-+ dialogSizer.Add(item = self.btnsizer, proportion = 0,
-+ flag = wx.ALIGN_CENTER)
-+
-+ border.Add(item = dialogSizer, proportion = 0,
-+ flag = wx.ALL, border = 5)
-+
-+ self.SetSizer(border)
-+ self.Layout()
-+ self.Fit()
-+
-+ # bindings
-+ self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
-+ self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
-+
-+ def _addSelectSizer(self, title, sel):
-+ """!Helper layout function.
-+ """
-+ selSizer = wx.BoxSizer(orient = wx.VERTICAL)
-+
-+ selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
-+ selTitleSizer.Add(item = title, proportion = 1,
-+ flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
-+
-+ selSizer.Add(item = selTitleSizer, proportion = 0,
-+ flag = wx.EXPAND)
-+
-+ selSizer.Add(item = sel, proportion = 1,
-+ flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
-+ border = 5)
-+
-+ return selSizer
-+
-+ def OnClose(self, event):
-+ """!Close dialog
-+ """
-+ if not self.IsModal():
-+ self.Destroy()
-+ event.Skip()
-+
-+ def OnOk(self, event):
-+ """!
-+ """
-+ band_1 = self.band_1_ch.GetSelection()
-+ band_2 = self.band_2_ch.GetSelection()
-+
-+
-+ if band_1 == band_2:
-+ GError(_("Selected bands must be different."))
-+ return
-+
-+ #TODO axes selection
-+ if band_1 > band_2:
-+ tmp_band = band_2
-+ band_2 = band_1
-+ band_1 = band_2
-+
-+ self.scatt_id = idBandsToidScatt(band_1, band_2, len(self.bands))
-+
-+ event.Skip()
-+
-+ def GetScattId(self):
-+ return self.scatt_id
-Index: gui/wxpython/scatt_plot/dialogs.py
-===================================================================
---- gui/wxpython/scatt_plot/dialogs.py (revision 0)
-+++ gui/wxpython/scatt_plot/dialogs.py (working copy)
-@@ -0,0 +1,142 @@
-+"""!
-+ at package scatt_plot.dialogs
-+
-+ at brief GUI.
-+
-+Classes:
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+import os
-+import sys
-+
-+import wx
-+from scatt_plot.sc_pl_core import idBandsToidScatt
-+
-+class AddScattPlotDialog(wx.Dialog):
-+
-+ def __init__(self, parent, bands, id = wx.ID_ANY):
-+
-+ wx.Dialog.__init__(self, parent, title = ("Add scatter plot"), id = id)
-+
-+ self.bands = bands
-+
-+ self.scatt_id = None
-+
-+ self._createWidgets()
-+
-+ def _createWidgets(self):
-+
-+ self.labels = {}
-+ self.params = {}
-+
-+ self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
-+
-+ self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+ choices = self.bands,
-+ style = wx.CB_READONLY, size = (350, 30))
-+
-+ self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 2:"))
-+
-+ self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+ choices = self.bands,
-+ style = wx.CB_READONLY, size = (350, 30))
-+
-+ # buttons
-+ self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
-+
-+ self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
-+
-+ self._layout()
-+
-+ def _layout(self):
-+
-+ border = wx.BoxSizer(wx.VERTICAL)
-+ dialogSizer = wx.BoxSizer(wx.VERTICAL)
-+
-+ regionSizer = wx.BoxSizer(wx.HORIZONTAL)
-+
-+ dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label,
-+ sel = self.band_1_ch))
-+
-+ dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label,
-+ sel = self.band_2_ch))
-+
-+ # buttons
-+ self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
-+
-+ self.btnsizer.Add(item = self.btn_close, proportion = 0,
-+ flag = wx.ALL | wx.ALIGN_CENTER,
-+ border = 10)
-+
-+ self.btnsizer.Add(item = self.btn_ok, proportion = 0,
-+ flag = wx.ALL | wx.ALIGN_CENTER,
-+ border = 10)
-+
-+ dialogSizer.Add(item = self.btnsizer, proportion = 0,
-+ flag = wx.ALIGN_CENTER)
-+
-+ border.Add(item = dialogSizer, proportion = 0,
-+ flag = wx.ALL, border = 5)
-+
-+ self.SetSizer(border)
-+ self.Layout()
-+ self.Fit()
-+
-+ # bindings
-+ self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
-+ self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
-+
-+ def _addSelectSizer(self, title, sel):
-+ """!Helper layout function.
-+ """
-+ selSizer = wx.BoxSizer(orient = wx.VERTICAL)
-+
-+ selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
-+ selTitleSizer.Add(item = title, proportion = 1,
-+ flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
-+
-+ selSizer.Add(item = selTitleSizer, proportion = 0,
-+ flag = wx.EXPAND)
-+
-+ selSizer.Add(item = sel, proportion = 1,
-+ flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
-+ border = 5)
-+
-+ return selSizer
-+
-+ def OnClose(self, event):
-+ """!Close dialog
-+ """
-+ if not self.IsModal():
-+ self.Destroy()
-+ event.Skip()
-+
-+ def OnOk(self, event):
-+ """!
-+ """
-+ band_1 = self.band_1_ch.GetSelection()
-+ band_2 = self.band_2_ch.GetSelection()
-+
-+
-+ if band_1 == band_2:
-+ GError(_("Selected bands must be different."))
-+ return
-+
-+ #TODO axes selection
-+ if band_1 > band_2:
-+ tmp_band = band_2
-+ band_2 = band_1
-+ band_1 = band_2
-+
-+ self.scatt_id = idBandsToidScatt(band_1, band_2, len(self.bands))
-+
-+ event.Skip()
-+
-+ def GetScattId(self):
-+ return self.scatt_id
-Index: gui/wxpython/scatt_plot/toolbars_iclass.py
-===================================================================
---- gui/wxpython/scatt_plot/toolbars_iclass.py (revision 0)
-+++ gui/wxpython/scatt_plot/toolbars_iclass.py (working copy)
-@@ -0,0 +1,106 @@
-+"""!
-+ at package scatt_plot.toolbars
-+
-+ at brief Scatter plot - toolbars
-+
-+Classes:
-+ - toolbars::MainToolbar
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+
-+
-+import wx
-+
-+from icons.icon import MetaIcon
-+from gui_core.toolbars import BaseToolbar, BaseIcons
-+from core.gcmd import RunCommand
-+from core.gcmd import GException, GError, RunCommand
-+from scatt_plot.sc_pl_core import idBandsToidScatt
-+
-+
-+class MainToolbar(BaseToolbar):
-+ """!Main toolbar
-+ """
-+ def __init__(self, parent, scatt_mgr):
-+ BaseToolbar.__init__(self, parent)
-+ self.scatt_mgr = scatt_mgr
-+
-+ self.InitToolbar(self._toolbarData())
-+
-+ # realize the toolbar
-+ self.Realize()
-+
-+ def _toolbarData(self):
-+
-+ icons = {
-+ 'settings' : BaseIcons['settings'].SetLabel( _('Ssettings')),
-+ 'help' : MetaIcon(img = 'help',
-+ label = _('Show manual')),
-+ 'add_scatt_pl' : MetaIcon(img = 'layer-raster-analyze',
-+ label = _('Add scatter plot')),
-+ 'editCatAdd' : MetaIcon(img = 'polygon-create',
-+ label = _('Add region to category mode')),
-+ 'editCatRemove' : MetaIcon(img = 'polygon-delete',
-+ label = _('Remove region to category mode')),
-+ 'pan' : MetaIcon(img = 'pan',
-+ label = _('Pan'),
-+ desc = _('Drag with mouse to pan scatter plots (zoom with holding right mouse button and draging')),
-+ 'zoomIn' : MetaIcon(img = 'zoom-in',
-+ label = _('Zoom in'),
-+ desc = _('Zoom with rectangle in scatter plots.')),
-+ 'cats_mgr' : MetaIcon(img = 'table-manager',
-+ label = _('Class manager'))
-+ }
-+
-+ return self._getToolbarData((
-+ ("cats_mgr", icons['cats_mgr'],
-+ lambda event: self.parent.ShowCategoryPanel(event.Checked()), wx.ITEM_CHECK),
-+ (None, ),
-+ ("pan", icons["pan"],
-+ lambda event: self.SetPloltsMode(event, 'pan'),
-+ wx.ITEM_CHECK),
-+ ("zoom", icons["zoomIn"],
-+ lambda event: self.SetPloltsMode(event, 'zoom'),
-+ wx.ITEM_CHECK),
-+ ('add', icons['editCatAdd'],
-+ lambda event: self.SetPloltsMode(event, 'add'),
-+ wx.ITEM_CHECK),
-+ ('remove', icons['editCatRemove'],
-+ lambda event: self.SetPloltsMode(event, 'remove'),
-+ wx.ITEM_CHECK),
-+ (None, ),
-+ ('add_scatt', icons["add_scatt_pl"],
-+ lambda event : self.scatt_mgr.AddScattPlot())
-+ #('settings', icon["settings"],
-+ # self.parent.OnSettings),
-+ #('help', icons["help"],
-+ # self.OnHelp),
-+ ))
-+
-+ def GetToolId(self, toolName): #TODO can be useful in base
-+
-+ return vars(self)[toolName]
-+
-+ def SetPloltsMode(self, event, tool_name):
-+
-+ #TODO move to toolbars
-+ if event.Checked() == True:
-+ for i_tool_data in self._data:
-+ i_tool_name = i_tool_data[0]
-+ if not i_tool_name or i_tool_name == "cats_mgr":
-+ continue
-+ if i_tool_name == tool_name:
-+ continue
-+ i_tool_id = vars(self)[i_tool_name]
-+
-+ self.ToggleTool(i_tool_id, False)
-+ self.scatt_mgr.SetPlotsMode(mode = tool_name)
-+ return
-+
-+ self.scatt_mgr.SetPlotsMode(mode = None)
-\ No newline at end of file
-Index: gui/wxpython/scatt_plot/toolbars.py
-===================================================================
---- gui/wxpython/scatt_plot/toolbars.py (revision 0)
-+++ gui/wxpython/scatt_plot/toolbars.py (working copy)
-@@ -0,0 +1,106 @@
-+"""!
-+ at package scatt_plot.toolbars
-+
-+ at brief Scatter plot - toolbars
-+
-+Classes:
-+ - toolbars::MainToolbar
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+
-+
-+import wx
-+
-+from icons.icon import MetaIcon
-+from gui_core.toolbars import BaseToolbar, BaseIcons
-+from core.gcmd import RunCommand
-+
-+class MainToolbar(BaseToolbar):
-+ """!Main toolbar
-+ """
-+ def __init__(self, parent):
-+ BaseToolbar.__init__(self, parent)
-+
-+ self.InitToolbar(self._toolbarData())
-+
-+ # realize the toolbar
-+ self.Realize()
-+
-+ def _toolbarData(self):
-+
-+ icons = {
-+ 'set_data' : MetaIcon(img = 'layer-raster-add',
-+ label = _('Set input raster data for plots')),
-+ 'settings' : BaseIcons['settings'].SetLabel( _('Ssettings')),
-+ 'help' : MetaIcon(img = 'help',
-+ label = _('Show manual')),
-+ 'add_scatt_pl' : MetaIcon(img = 'layer-raster-analyze',
-+ label = _('Add scatter plot'))
-+ }
-+
-+ return self._getToolbarData((
-+ ('sat_data', icons["set_data"],
-+ self.parent.OnSetData),
-+ (None, ),
-+ ('add_scatt', icons["add_scatt_pl"],
-+ self.parent.OnAddScattPl),
-+ #('settings', icons["settings"],
-+ # self.parent.OnSettings),
-+ #('help', icons["help"],
-+ # self.OnHelp),
-+ ("quit", BaseIcons['quit'],
-+ self.parent.OnCloseDialog)
-+ ))
-+
-+ def OnHelp(self, event) :
-+ RunCommand('g.manual',
-+ entry = 'wxGUI.scatt_plot')
-+
-+class CategoriesToolbar(BaseToolbar):
-+
-+ def __init__(self, parent, cats_list, scatts_dlg):
-+ BaseToolbar.__init__(self, parent)
-+ self.cats_list = cats_list
-+ self.scatts_dlg = scatts_dlg
-+
-+ self.InitToolbar(self._toolbarData())
-+
-+
-+ # realize the toolbar
-+ self.Realize()
-+
-+
-+ def _toolbarData(self):
-+
-+ icons = {
-+ 'editCatAdd' : MetaIcon(img = 'polygon-create',
-+ label = _('Add region to category mode')),
-+ 'editCatRemove' : MetaIcon(img = 'polygon-delete',
-+ label = _('Remove region to category mode')),
-+ 'addCat' : MetaIcon(img = 'layer-add',
-+ label = _('Add category')),
-+ 'deleteCat' : MetaIcon(img = 'layer-remove',
-+ label = _('Delete category'))
-+ }
-+
-+ return self._getToolbarData((('editCatAdd', icons['editCatAdd'],
-+ lambda event: self.scatts_dlg.EditCatAdd(),
-+ wx.ITEM_CHECK),
-+ ('editCatRemove', icons['editCatRemove'],
-+ lambda event: self.scatts_dlg.EditCatRemove(),
-+ wx.ITEM_CHECK),
-+ (None, ),
-+ ('addCat', icons["addCat"],
-+ lambda event: self.cats_list.AddCategory()),
-+ ('deleteCat', icons["deleteCat"],
-+ lambda event: self.cats_list.DeleteCategory())))
-+
-+ def GetToolId(self, toolName): #TODO can be useful in base
-+
-+ return vars(self)[toolName]
-\ No newline at end of file
Index: gui/wxpython/scatt_plot/core_c.py
===================================================================
--- gui/wxpython/scatt_plot/core_c.py (revision 0)
+++ gui/wxpython/scatt_plot/core_c.py (working copy)
-@@ -0,0 +1,226 @@
+@@ -0,0 +1,167 @@
+"""!
+ at package scatt_plot.scatt_plot
+
@@ -1409,26 +119,21 @@
+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
+"""
+
++import sys
+from multiprocessing import Process, Queue
+
+from ctypes import *
+try:
+ from grass.lib.imagery import *
+ from grass.lib.gis import Cell_head, G_get_window
-+ #from grass.lib.raster import struct_Range
-+
-+
+except ImportError, e:
+ sys.stderr.write(_("Loading imagery lib failed"))
+
-+def ComputeScatts(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out):
++from core.gcmd import GException
+
-+ return _computeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out, None)
+
-+ # Queue object for interprocess communication
++def ComputeScatts(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out):
+ q = Queue()
-+
-+ # The separate render process
+ p = Process(target=_computeScattsProcess, args=(region, scatt_conds, bands,
+ n_bands, scatts, cats_rasts_in, cats_rasts_out, q))
+ p.start()
@@ -1438,20 +143,13 @@
+ return ret[0], ret[1]
+
+def UpdateCatRast(patch_rast, region, cat_rast):
-+
-+ #return _computeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts, None)
-+ # Queue object for interprocess communication
-+
-+ #_updateCatRastProcess(patch_rast, region, cat_rast, None)
-+ #return
+ q = Queue()
-+ # The separate render process
+ p = Process(target=_updateCatRastProcess, args=(patch_rast, region, cat_rast, q))
+ p.start()
-+ #ret = q.get()
++ ret = q.get()
+ p.join()
+
-+ #return ret[0], ret[1]
++ return ret
+
+def CreateCatRast(region, cat_rast):
+
@@ -1461,8 +159,8 @@
+def _computeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out, output_queue):
+
+ #TODO names for types not 0 and 1?
-+ sccats_c, vals_dt = _getComputationStruct(scatts, 0, n_bands)
-+ scatt_conds_c, vals_dt2 = _getComputationStruct(scatt_conds, 1, n_bands)
++ sccats_c, refs = _getComputationStruct(scatts, 0, n_bands)
++ scatt_conds_c, refs2 = _getComputationStruct(scatt_conds, 1, n_bands)
+
+ char_bands = _stringListToCharArr(bands)
+ char_cats_rasts_out = _stringListToCharArr(cats_rasts_out)
@@ -1472,17 +170,16 @@
+
+ ret = I_compute_scatts(pointer(cell_head),
+ pointer(scatt_conds_c),
++ pointer(char_cats_rasts_in),
+ pointer(char_bands),
+ n_bands,
-+ pointer(char_cats_rasts_in),
+ pointer(sccats_c),
+ pointer(char_cats_rasts_out))
+
+ I_sc_free_cats(pointer(sccats_c))
+ I_sc_free_cats(pointer(scatt_conds_c))
+
-+ #output_queue.put((ret, scatts))
-+ return (ret, scatts)
++ output_queue.put((ret, scatts))
+
+def _getBandcRange( band_info):
+ band_c_range = struct_Range()
@@ -1532,22 +229,15 @@
+ sccats = struct_scCats()
+ I_sc_init_cats(pointer(sccats), c_int(n_bands), c_int(cats_type));
+
-+ #for i in range(sccats.n_a_cats):
-+ # cat_id = sccats.cats_ids[i]
-+ # I_sc_delete_cat(pointer(sccats), cat_id)
-+ # i -= 1
-+
-+ vals_dt = []
++ refs = []
+ for cat_id, scatt_ids in cats.iteritems():
-+ I_sc_add_cat(pointer(sccats), cat_id)
++ cat_c_id = I_sc_add_cat(pointer(sccats))
+
+ for scatt_id, dt in scatt_ids.iteritems():
+ # if key is missing condition is always True (full scatter plor is computed)
+ if cats[cat_id].has_key(scatt_id):
+
+ vals = dt['np_vals']
-+ b1_info = dt['bands_info']['b1']
-+ b2_info = dt['bands_info']['b2']
+
+ scatt_vals = scdScattData()
+
@@ -1559,67 +249,28 @@
+ pass
+ else:
+ return None
-+
-+ b1_c_info = _getBandcRange(b1_info)
-+ b2_c_info =_getBandcRange(b2_info)
+ data_p = vals.ctypes.data_as(c_void_p)
-+ I_scd_init_scatt_data(pointer(scatt_vals), cats_type, len(vals), data_p,
-+ b1_c_info, b2_c_info)
++ I_scd_init_scatt_data(pointer(scatt_vals), cats_type, len(vals), data_p)
+
-+ vals_dt.append(scatt_vals)
++ refs.append(scatt_vals)
+
+ I_sc_insert_scatt_data(pointer(sccats),
+ pointer(scatt_vals),
-+ cat_id, scatt_id)
++ cat_c_id, scatt_id)
+
-+ return sccats, vals_dt
++ return sccats, refs
+
+def _updateCatRastProcess(patch_rast, region, cat_rast, output_queue):
-+
-+ #TODO names for types not 0 and 1?
-+
+ cell_head = _regionToCellHead(region)
+
+
-+ I_insert_patch_to_cat_rast(patch_rast,
-+ pointer(cell_head),
-+ cat_rast)
++ ret = I_insert_patch_to_cat_rast(patch_rast,
++ pointer(cell_head),
++ cat_rast)
+
-+ #print re
-+ #output_queue.put((ret, scatts))
-+ #return (ret, scatts)
++ output_queue.put(ret)
+
-+"""
-+class A:
-+ def __init__(self):
-+ self.i = 0
+
-+ def incr(self):
-+ self.i += 1
-+ return self.i
-+
-+def worker(input, output):
-+ print "ahoj"
-+ for func, args in iter(input.get, 'STOP'):
-+ print "jedu"
-+ result = func.incr
-+ output.put(result)
-+
-+def test():
-+ # Create queues
-+ task_queue = Queue()
-+ done_queue = Queue()
-+
-+ # Start worker processes
-+ a = A()
-+
-+ prc = Process(target=worker, args=(task_queue, done_queue)).start()
-+ task_queue.put((a,1))
-+
-+ data = done_queue.get()
-+ print data
-+ task_queue.put('STOP')
-+"""
Index: gui/wxpython/scatt_plot/__init__.py
===================================================================
--- gui/wxpython/scatt_plot/__init__.py (revision 0)
@@ -2436,7 +1087,7 @@
===================================================================
--- gui/wxpython/scatt_plot/sc_pl_core.py (revision 0)
+++ gui/wxpython/scatt_plot/sc_pl_core.py (working copy)
-@@ -0,0 +1,619 @@
+@@ -0,0 +1,627 @@
+"""!
+ at package scatt_plot.scatt_plot
+
@@ -2563,6 +1214,8 @@
+ returncode, scatts = ComputeScatts(self.an_data.GetRegion(), scatt_conds, bands,
+ len(self.GetBands()), scatts, cats_rasts_conds, cats_rasts)
+
++ if returncode < 0:
++ GException(_("Computing of scatter plots failed."))
+ #self.scatts_dt.SetData(scatts)
+
+ def CatRastUpdater(self):
@@ -2625,10 +1278,11 @@
+ self._rasterize(grass_region, layer, cat, patch_rast)
+
+ region = self.an_data.GetRegion()
-+ UpdateCatRast(patch_rast, region, self.scatts_dt.GetCatRastCond(cat))
-+
++ ret = UpdateCatRast(patch_rast, region, self.scatts_dt.GetCatRastCond(cat))
++ if ret < 0:
++ GException(_("Patching category raster conditions file failed."))
+ RunCommand("g.remove",
-+ rast = patch_rast)#,
++ rast = patch_rast)
+
+ def _rasterize(self, grass_region, layer, cat, out_rast):
+
@@ -2636,7 +1290,9 @@
+ ret, text, msg = RunCommand("v.build",
+ map = self.vectMap,
+ getErrorMsg = True,
-+ read = True)#,
++ read = True)
++ if ret != 0:
++ GException(_("v.build failed:\n%s" % msg))
+
+ #TODO thread problem with env variable remove it!!!!
+ environs = os.environ.copy()
@@ -2652,6 +1308,10 @@
+ read = True,
+ overwrite = True,
+ env = environs)
++
++ if ret != 0:
++ GException(_("v.to.rast failed:\n%s" % msg))
++
+ def _create_grass_region_env(self, bbox):
+
+ region = self.an_data.GetRegion()
@@ -2944,10 +1604,9 @@
+ else:
+ self.cats_rasts_conds[cat_id] = grass.tempfile()
+ self.cats_rasts[cat_id] = "temp_cat_rast_%d" % cat_id
++ region = self.an_data.GetRegion()
++ CreateCatRast(region, self.cats_rasts_conds[cat_id])
+
-+ region = self.an_data.GetRegion()
-+ CreateCatRast(region, self.cats_rasts_conds[cat_id])
-+
+ return cat_id
+
+ def DeleteCategory(self, cat_id):
@@ -3056,60 +1715,1007 @@
+
+ return scatt_id
+
-Index: gui/wxpython/Makefile
+Index: gui/wxpython/scatt_plot/gthreading.py
===================================================================
---- gui/wxpython/Makefile (revision 57437)
-+++ gui/wxpython/Makefile (working copy)
-@@ -13,7 +13,7 @@
- $(wildcard animation/* core/*.py dbmgr/* gcp/*.py gmodeler/* \
- gui_core/*.py iclass/* lmgr/*.py location_wizard/*.py mapwin/*.py mapdisp/*.py \
- mapswipe/* modules/*.py nviz/*.py psmap/* rlisetup/* vdigit/* \
-- vnet/*.py web_services/*.py wxplot/*.py) \
-+ vnet/*.py web_services/*.py wxplot/*.py scatt_plot/*.py) \
- gis_set.py gis_set_error.py wxgui.py README
-
- DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES)) \
-@@ -21,7 +21,7 @@
-
- PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,animation core dbmgr gcp gmodeler \
- gui_core iclass lmgr location_wizard mapwin mapdisp modules nviz psmap \
-- mapswipe vdigit wxplot web_services rlisetup vnet)
-+ mapswipe vdigit wxplot web_services rlisetup vnet scatt_plot)
-
- DSTDIRS := $(patsubst %,$(ETCDIR)/%,icons scripts xml)
-
-Index: gui/wxpython/vdigit/toolbars.py
+--- gui/wxpython/scatt_plot/gthreading.py (revision 0)
++++ gui/wxpython/scatt_plot/gthreading.py (working copy)
+@@ -0,0 +1,134 @@
++"""!
++ at package scatt_plot.gthreading
++
++Classes:
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++
++import os
++import sys
++import time
++import threading
++import Queue
++
++import wx
++from core.gconsole import wxCmdRun, wxCmdDone, wxCmdPrepare
++
++class gThread(threading.Thread):
++ """!Thread for GRASS commands"""
++ requestId = 0
++
++ def __init__(self, receiver, requestQ=None, resultQ=None, **kwds):
++ """!
++ @param receiver event receiver (used in PostEvent)
++ """
++ threading.Thread.__init__(self, **kwds)
++
++ if requestQ is None:
++ self.requestQ = Queue.Queue()
++ else:
++ self.requestQ = requestQ
++
++ if resultQ is None:
++ self.resultQ = Queue.Queue()
++ else:
++ self.resultQ = resultQ
++
++ self.setDaemon(True)
++
++ self.receiver = receiver
++ self._want_abort_all = False
++
++ self.start()
++
++ def Run(self, *args, **kwds):
++ """!Run command in queue
++
++ @param args unnamed command arguments
++ @param kwds named command arguments
++
++ @return request id in queue
++ """
++ gThread.requestId += 1
++ self.requestQ.put((gThread.requestId, args, kwds))
++
++ return gThread.requestId
++
++ def GetId(self):
++ """!Get id for next command"""
++ return gThread.requestId + 1
++
++ def SetId(self, id):
++ """!Set starting id"""
++ gThread.requestId = id
++
++ def run(self):
++ os.environ['GRASS_MESSAGE_FORMAT'] = 'gui'
++ while True:
++ requestId, args, kwds = self.requestQ.get()
++ for key in ('callable', 'onDone', 'onPrepare', 'userData'):
++ if key in kwds:
++ vars()[key] = kwds[key]
++ del kwds[key]
++ else:
++ vars()[key] = None
++
++ requestTime = time.time()
++
++ #if self._want_abort_all and self.requestCmd is not None:
++ # self.requestCmd.abort()
++ # if self.requestQ.empty():
++ # self._want_abort_all = False
++
++ # prepare
++ if self.receiver:
++ event = wxCmdPrepare(type = 'method',
++ time=requestTime,
++ pid=requestId)
++
++ wx.PostEvent(self.receiver, event)
++
++ # run command
++ event = wxCmdRun(type = 'method',
++ pid=requestId)
++
++ wx.PostEvent(self.receiver, event)
++
++ time.sleep(.1)
++
++ ret = None
++ exception = None
++
++ #to
++ #try:
++ ret = vars()['callable'](*args, **kwds)
++ #except Exception as e:
++ # exception = e;
++
++ self.resultQ.put((requestId, ret))
++
++ time.sleep(.1)
++
++ if self.receiver:
++ event = wxCmdDone(type = 'cmd',
++ kwds = kwds,
++ args = args, #TODO expand args to kwds
++ ret=ret,
++ exception=exception,
++ pid=requestId)
++
++ # send event
++ wx.PostEvent(self.receiver, event)
++
++ def abort(self, abortall=True):
++ """!Abort command(s)"""
++ if abortall:
++ self._want_abort_all = True
++ if self.requestQ.empty():
++ self._want_abort_all = False
+\ No newline at end of file
+Index: gui/wxpython/scatt_plot/dialogs_iclass.py
===================================================================
---- gui/wxpython/vdigit/toolbars.py (revision 57437)
-+++ gui/wxpython/vdigit/toolbars.py (working copy)
-@@ -17,6 +17,7 @@
- import wx
-
- from grass.script import core as grass
-+from grass.pydispatch.signal import Signal
-
- from gui_core.toolbars import BaseToolbar, BaseIcons
- from gui_core.dialogs import CreateNewVector
-@@ -42,6 +43,8 @@
- self.digit = None
- self._giface = giface
-
-+ self.editingStarted = Signal("VDigitToolbar.editingStarted")
+--- gui/wxpython/scatt_plot/dialogs_iclass.py (revision 0)
++++ gui/wxpython/scatt_plot/dialogs_iclass.py (working copy)
+@@ -0,0 +1,436 @@
++"""!
++ at package scatt_plot.dialogs
+
- # currently selected map layer for editing (reference to MapLayer instance)
- self.mapLayer = None
- # list of vector layers from Layer Manager (only in the current mapset)
-@@ -818,6 +821,7 @@
- alpha = int(opacity * 255)
- self.digit.GetDisplay().UpdateSettings(alpha = alpha)
++ at brief GUI.
++
++Classes:
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++import os
++import sys
++
++import wx
++import wx.lib.scrolledpanel as scrolled
++import wx.lib.mixins.listctrl as listmix
++import wx.lib.flatnotebook as FN
++import wx.aui
++
++from core import globalvar
++from core.gcmd import GException, GError, RunCommand
++
++from gui_core.gselect import Select
++
++from scatt_plot.controllers import ScattsManager
++from scatt_plot.toolbars_iclass import MainToolbar
++from scatt_plot.sc_pl_core import idScattToidBands
++from scatt_plot.plots import ScatterPlotWidget
++
++try:
++ from agw import aui
++except ImportError:
++ import wx.lib.agw.aui as aui
++
++class IClassScatterPlotsPanel(wx.Panel):
++ def __init__(self, parent, giface, iclass_mapwin = None,
++ id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
++
++ #wx.SplitterWindow.__init__(self, parent = parent, id = id,
++ # style = wx.SP_LIVE_UPDATE)
++ wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
++
++ #self.head_panel = wx.Panel(parent = self, id = wx.ID_ANY)
++ self.scatt_mgr = ScattsManager(guiparent = self, giface = giface, iclass_mapwin = iclass_mapwin)
++
++ # toobars
++ self.toolbars = {}
++ self.toolbars['mainToolbar'] = MainToolbar(parent = self, scatt_mgr = self.scatt_mgr)
++ self._createCategoryPanel(self)
++
++ self.plot_panel = IClassPlotPanel(self, self.scatt_mgr)
++
++ mainsizer = wx.BoxSizer(wx.VERTICAL)
++ mainsizer.Add(item = self.toolbars['mainToolbar'], proportion = 0, flag = wx.EXPAND)
++ mainsizer.Add(item = self.catsPanel, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT , border = 5)
++ mainsizer.Add(item = self.plot_panel, proportion = 1, flag = wx.EXPAND)
++ self.catsPanel.Hide()
++ self.SetSizer(mainsizer)
++
++
++ #self.SetSashGravity(0.5)
++ #self.SplitHorizontally(self.head_panel, self.plot_panel, -50)
++ self.Layout()
++ #self.SetAutoLayout(1)
++
++ def NewScatterPlot(self, scatt_id):
++ return self.plot_panel.NewScatterPlot(scatt_id)
++
++ def ShowCategoryPanel(self, show):
++ self.catsPanel.Show(show)
++
++ #if show:
++ # self.SetSashSize(5)
++ #else:
++ # self.SetSashSize(0)
++ self.plot_panel.SetVirtualSize(self.plot_panel.GetBestVirtualSize())
++ self.Layout()
++
++ def _createCategoryPanel(self, parent):
++ self.catsPanel = wx.Panel(parent = parent)
++ self.cats_list = CategoryListCtrl(parent = self.catsPanel,
++ cats_mgr = self.scatt_mgr.GetCategoriesManager())
++
++ self.catsPanel.SetMaxSize((-1, 150))
++
++ box_capt = wx.StaticBox(parent = self.catsPanel, id = wx.ID_ANY,
++ label = ' %s ' % _("Classes manager for scatter plots"))
++ catsSizer = wx.StaticBoxSizer(box_capt, wx.VERTICAL)
++
++ catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND | wx.ALL)
++ self.catsPanel.SetSizer(catsSizer)
++
++
++class IClassPlotPanel(scrolled.ScrolledPanel):
++ def __init__(self, parent, scatt_mgr, id = wx.ID_ANY):
++
++ scrolled.ScrolledPanel.__init__(self, parent)
++ self.SetupScrolling(scroll_x = False, scroll_y = True)
++
++ self.scatt_mgr = scatt_mgr
++
++ self.mainPanel = wx.Panel(parent = self, id = wx.ID_ANY)
++
++ #self._createCategoryPanel()
++ # Fancy gui
++ self._mgr = aui.AuiManager(self.mainPanel)
++ #self._mgr.SetManagedWindow(self)
++
++ self._mgr.Update()
++
++ self._doLayout()
++ self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
++
++ dlgSize = (-1, 400)
++ #self.SetBestSize(dlgSize)
++ #self.SetInitialSize(dlgSize)
++ self.SetAutoLayout(1)
++ #fix goutput's pane size (required for Mac OSX)
++ #if self.gwindow:
++ # self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
++
++ def OnScroll(self, event):
++ event.Skip()
++ wx.CallAfter(self._mgr.Update)
++ wx.CallAfter(self.Layout)
++
++ def _doLayout(self):
++
++ mainsizer = wx.BoxSizer(wx.VERTICAL)
++ mainsizer.Add(item = self.mainPanel, proportion = 1, flag = wx.EXPAND)
++ self.SetSizer(mainsizer)
++
++ self.Layout()
++ self.SetupScrolling()
++
++ def OnCloseDialog(self, event):
++ """!Close dialog"""
++ self.scatt_mgr.CleanUp()
++ self.Destroy()
++
++ def OnSettings(self, event):
++ pass
++
++ def NewScatterPlot(self, scatt_id):
++ #TODO needs to be resolved (should be in this class)
++
++ scatt = ScatterPlotWidget(parent = self.mainPanel,
++ scatt_mgr = self.scatt_mgr,
++ scatt_id = scatt_id)
++
++ bands = self.scatt_mgr.GetBands()
++ #TODO too low level
++ b1_id, b2_id = idScattToidBands(scatt_id, len(bands))
++
++ self._mgr.AddPane(scatt,
++ aui.AuiPaneInfo().Dockable(True).Floatable(True).
++ Name("scatter plot %d" % scatt_id).MinSize((-1, 300)).Caption(("%s x: %s y: %s") % (_("scatter plot"), bands[b1_id], bands[b2_id])).
++ Center().Position(1).MaximizeButton(True).
++ MinimizeButton(True).CaptionVisible(True).
++ CloseButton(True).Layer(0))
++ self._mgr.Update()
++
++ self.SetVirtualSize(self.GetBestVirtualSize())
++ self.Layout()
++
++ return scatt
++
++ def GetScattMgr(self):
++ return self.scatt_mgr
++
++class CategoryListCtrl(wx.ListCtrl,
++ listmix.ListCtrlAutoWidthMixin,
++ listmix.TextEditMixin):
++
++ def __init__(self, parent, cats_mgr, id = wx.ID_ANY):
++
++ wx.ListCtrl.__init__(self, parent, id,
++ style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES)
++ self.columns = ((_('Class name'), 'name'),
++ (_('Color'), 'color'))
++ self.Populate(columns = self.columns)
++
++ self.cats_mgr = cats_mgr
++ self.SetItemCount(len(self.cats_mgr.GetCategories()))
++
++ self.rightClickedItemIdx = wx.NOT_FOUND
++
++ listmix.ListCtrlAutoWidthMixin.__init__(self)
++
++ listmix.TextEditMixin.__init__(self)
++
++ self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnEdit)
++ self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSel)
++
++ self.cats_mgr.setCategoryAttrs.connect(self.Update)
++ self.cats_mgr.deletedCategory.connect(self.Update)
++ self.cats_mgr.addedCategory.connect(self.Update)
++
++ def Update(self, **kwargs):
++ self.SetItemCount(len(self.cats_mgr.GetCategories()))
++ self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++
++ def InitCoreCats(self):
++ self.SetItemCount(len(self.cats_mgr.GetCategories()))
++ self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++
++ def SetVirtualData(self, row, column, text):
++ attr = self.columns[column][1]
++ if attr == 'name':
++ try:
++ text.encode('ascii')
++ except UnicodeEncodeError:
++ GMessage(parent = self, message = _("Please use only ASCII characters."))
++ return
++
++ cat_id = self.cats_mgr.GetCategories()[row]
++
++ self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
++ self.cats_mgr.SetCategoryAttrs(cat_id, {attr : text})
++ self.cats_mgr.setCategoryAttrs.connect(self.Update)
++
++ self.Select(row)
++
++ def Populate(self, columns):
++ for i, col in enumerate(columns):
++ self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
++
++ self.SetColumnWidth(0, 100)
++ self.SetColumnWidth(1, 100)
++
++ def AddCategory(self):
++
++ self.cats_mgr.addedCategory.disconnect(self.Update)
++ cat_id = self.cats_mgr.AddCategory()
++ self.cats_mgr.addedCategory.connect(self.Update)
++
++ if cat_id < 0:
++ GError(_("Maximum limit of categories number was reached."))
++ return
++ self.SetItemCount(len(self.cats_mgr.GetCategories()))
++
++ def DeleteCategory(self):
++ indexList = sorted(self.GetSelectedIndices(), reverse = True)
++ cats = []
++ for i in indexList:
++ # remove temporary raster
++ cat_id = self.cats_mgr.GetCategories()[i]
++
++ cats.append(cat_id)
++
++ self.cats_mgr.deletedCategory.disconnect(self.Update)
++ self.cats_mgr.DeleteCategory(cat_id)
++ self.cats_mgr.deletedCategory.connect(self.Update)
++
++ self.SetItemCount(len(self.cats_mgr.GetCategories()))
++
++ def OnSel(self, event):
++ event.Skip()
++
++ def GetSelectedIndices(self, state = wx.LIST_STATE_SELECTED):
++ indices = []
++ lastFound = -1
++ while True:
++ index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state)
++ if index == -1:
++ break
++ else:
++ lastFound = index
++ indices.append(index)
++ return indices
++
++ def OnEdit(self, event):
++ currentItem = event.m_itemIndex
++ currentCol = event.m_col
++
++ if currentCol == 1:
++ dlg = wx.ColourDialog(self)
++ dlg.GetColourData().SetChooseFull(True)
++
++ if dlg.ShowModal() == wx.ID_OK:
++ color = dlg.GetColourData().GetColour().Get()
++ color = ':'.join(map(str, color))
++ self.SetVirtualData(currentItem, currentCol, color)
++ dlg.Destroy()
++ wx.CallAfter(self.SetFocus)
++
++ event.Skip()
++
++
++ def DeselectAll(self):
++ """!Deselect all items"""
++ indexList = self.GetSelectedIndices()
++ for i in indexList:
++ self.Select(i, on = 0)
++
++ # no highlight
++ self.OnCategorySelected(None)
++
++ def OnGetItemText(self, item, col):
++ attr = self.columns[col][1]
++ cat_id = self.cats_mgr.GetCategories()[item]
++
++ return self.cats_mgr.GetCategoryAttrs(cat_id)[attr]
++
++ def OnGetItemImage(self, item):
++ return -1
++
++ def OnGetItemAttr(self, item):
++ return None
++
++class AddScattPlotDialog(wx.Dialog):
++
++ def __init__(self, parent, bands, id = wx.ID_ANY):
++
++ wx.Dialog.__init__(self, parent, title = ("Add scatter plot"), id = id)
++
++ self.bands = bands
++
++ self.scatt_id = None
++
++ self._createWidgets()
++
++ def _createWidgets(self):
++
++ self.labels = {}
++ self.params = {}
++
++ self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
++
++ self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
++ choices = self.bands,
++ style = wx.CB_READONLY, size = (350, 30))
++
++ self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 2:"))
++
++ self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
++ choices = self.bands,
++ style = wx.CB_READONLY, size = (350, 30))
++
++ # buttons
++ self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
++
++ self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
++
++ self._layout()
++
++ def _layout(self):
++
++ border = wx.BoxSizer(wx.VERTICAL)
++ dialogSizer = wx.BoxSizer(wx.VERTICAL)
++
++ regionSizer = wx.BoxSizer(wx.HORIZONTAL)
++
++ dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label,
++ sel = self.band_1_ch))
++
++ dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label,
++ sel = self.band_2_ch))
++
++ # buttons
++ self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
++
++ self.btnsizer.Add(item = self.btn_close, proportion = 0,
++ flag = wx.ALL | wx.ALIGN_CENTER,
++ border = 10)
++
++ self.btnsizer.Add(item = self.btn_ok, proportion = 0,
++ flag = wx.ALL | wx.ALIGN_CENTER,
++ border = 10)
++
++ dialogSizer.Add(item = self.btnsizer, proportion = 0,
++ flag = wx.ALIGN_CENTER)
++
++ border.Add(item = dialogSizer, proportion = 0,
++ flag = wx.ALL, border = 5)
++
++ self.SetSizer(border)
++ self.Layout()
++ self.Fit()
++
++ # bindings
++ self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
++ self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
++
++ def _addSelectSizer(self, title, sel):
++ """!Helper layout function.
++ """
++ selSizer = wx.BoxSizer(orient = wx.VERTICAL)
++
++ selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
++ selTitleSizer.Add(item = title, proportion = 1,
++ flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
++
++ selSizer.Add(item = selTitleSizer, proportion = 0,
++ flag = wx.EXPAND)
++
++ selSizer.Add(item = sel, proportion = 1,
++ flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
++ border = 5)
++
++ return selSizer
++
++ def OnClose(self, event):
++ """!Close dialog
++ """
++ if not self.IsModal():
++ self.Destroy()
++ event.Skip()
++
++ def OnOk(self, event):
++ """!
++ """
++ band_1 = self.band_1_ch.GetSelection()
++ band_2 = self.band_2_ch.GetSelection()
++
++
++ if band_1 == band_2:
++ GError(_("Selected bands must be different."))
++ return
++
++ #TODO axes selection
++ if band_1 > band_2:
++ tmp_band = band_2
++ band_2 = band_1
++ band_1 = band_2
++
++ self.scatt_id = idBandsToidScatt(band_1, band_2, len(self.bands))
++
++ event.Skip()
++
++ def GetScattId(self):
++ return self.scatt_id
+Index: gui/wxpython/scatt_plot/dialogs.py
+===================================================================
+--- gui/wxpython/scatt_plot/dialogs.py (revision 0)
++++ gui/wxpython/scatt_plot/dialogs.py (working copy)
+@@ -0,0 +1,142 @@
++"""!
++ at package scatt_plot.dialogs
++
++ at brief GUI.
++
++Classes:
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++import os
++import sys
++
++import wx
++from scatt_plot.sc_pl_core import idBandsToidScatt
++
++class AddScattPlotDialog(wx.Dialog):
++
++ def __init__(self, parent, bands, id = wx.ID_ANY):
++
++ wx.Dialog.__init__(self, parent, title = ("Add scatter plot"), id = id)
++
++ self.bands = bands
++
++ self.scatt_id = None
++
++ self._createWidgets()
++
++ def _createWidgets(self):
++
++ self.labels = {}
++ self.params = {}
++
++ self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
++
++ self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
++ choices = self.bands,
++ style = wx.CB_READONLY, size = (350, 30))
++
++ self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 2:"))
++
++ self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
++ choices = self.bands,
++ style = wx.CB_READONLY, size = (350, 30))
++
++ # buttons
++ self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
++
++ self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
++
++ self._layout()
++
++ def _layout(self):
++
++ border = wx.BoxSizer(wx.VERTICAL)
++ dialogSizer = wx.BoxSizer(wx.VERTICAL)
++
++ regionSizer = wx.BoxSizer(wx.HORIZONTAL)
++
++ dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label,
++ sel = self.band_1_ch))
++
++ dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label,
++ sel = self.band_2_ch))
++
++ # buttons
++ self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
++
++ self.btnsizer.Add(item = self.btn_close, proportion = 0,
++ flag = wx.ALL | wx.ALIGN_CENTER,
++ border = 10)
++
++ self.btnsizer.Add(item = self.btn_ok, proportion = 0,
++ flag = wx.ALL | wx.ALIGN_CENTER,
++ border = 10)
++
++ dialogSizer.Add(item = self.btnsizer, proportion = 0,
++ flag = wx.ALIGN_CENTER)
++
++ border.Add(item = dialogSizer, proportion = 0,
++ flag = wx.ALL, border = 5)
++
++ self.SetSizer(border)
++ self.Layout()
++ self.Fit()
++
++ # bindings
++ self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
++ self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
++
++ def _addSelectSizer(self, title, sel):
++ """!Helper layout function.
++ """
++ selSizer = wx.BoxSizer(orient = wx.VERTICAL)
++
++ selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
++ selTitleSizer.Add(item = title, proportion = 1,
++ flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
++
++ selSizer.Add(item = selTitleSizer, proportion = 0,
++ flag = wx.EXPAND)
++
++ selSizer.Add(item = sel, proportion = 1,
++ flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
++ border = 5)
++
++ return selSizer
++
++ def OnClose(self, event):
++ """!Close dialog
++ """
++ if not self.IsModal():
++ self.Destroy()
++ event.Skip()
++
++ def OnOk(self, event):
++ """!
++ """
++ band_1 = self.band_1_ch.GetSelection()
++ band_2 = self.band_2_ch.GetSelection()
++
++
++ if band_1 == band_2:
++ GError(_("Selected bands must be different."))
++ return
++
++ #TODO axes selection
++ if band_1 > band_2:
++ tmp_band = band_2
++ band_2 = band_1
++ band_1 = band_2
++
++ self.scatt_id = idBandsToidScatt(band_1, band_2, len(self.bands))
++
++ event.Skip()
++
++ def GetScattId(self):
++ return self.scatt_id
+Index: gui/wxpython/scatt_plot/toolbars_iclass.py
+===================================================================
+--- gui/wxpython/scatt_plot/toolbars_iclass.py (revision 0)
++++ gui/wxpython/scatt_plot/toolbars_iclass.py (working copy)
+@@ -0,0 +1,106 @@
++"""!
++ at package scatt_plot.toolbars
++
++ at brief Scatter plot - toolbars
++
++Classes:
++ - toolbars::MainToolbar
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++
++
++import wx
++
++from icons.icon import MetaIcon
++from gui_core.toolbars import BaseToolbar, BaseIcons
++from core.gcmd import RunCommand
++from core.gcmd import GException, GError, RunCommand
++from scatt_plot.sc_pl_core import idBandsToidScatt
++
++
++class MainToolbar(BaseToolbar):
++ """!Main toolbar
++ """
++ def __init__(self, parent, scatt_mgr):
++ BaseToolbar.__init__(self, parent)
++ self.scatt_mgr = scatt_mgr
++
++ self.InitToolbar(self._toolbarData())
++
++ # realize the toolbar
++ self.Realize()
++
++ def _toolbarData(self):
++
++ icons = {
++ 'settings' : BaseIcons['settings'].SetLabel( _('Ssettings')),
++ 'help' : MetaIcon(img = 'help',
++ label = _('Show manual')),
++ 'add_scatt_pl' : MetaIcon(img = 'layer-raster-analyze',
++ label = _('Add scatter plot')),
++ 'editCatAdd' : MetaIcon(img = 'polygon-create',
++ label = _('Add region to category mode')),
++ 'editCatRemove' : MetaIcon(img = 'polygon-delete',
++ label = _('Remove region to category mode')),
++ 'pan' : MetaIcon(img = 'pan',
++ label = _('Pan'),
++ desc = _('Drag with mouse to pan scatter plots (zoom with holding right mouse button and draging')),
++ 'zoomIn' : MetaIcon(img = 'zoom-in',
++ label = _('Zoom in'),
++ desc = _('Zoom with rectangle in scatter plots.')),
++ 'cats_mgr' : MetaIcon(img = 'table-manager',
++ label = _('Class manager'))
++ }
++
++ return self._getToolbarData((
++ ("cats_mgr", icons['cats_mgr'],
++ lambda event: self.parent.ShowCategoryPanel(event.Checked()), wx.ITEM_CHECK),
++ (None, ),
++ ("pan", icons["pan"],
++ lambda event: self.SetPloltsMode(event, 'pan'),
++ wx.ITEM_CHECK),
++ ("zoom", icons["zoomIn"],
++ lambda event: self.SetPloltsMode(event, 'zoom'),
++ wx.ITEM_CHECK),
++ ('add', icons['editCatAdd'],
++ lambda event: self.SetPloltsMode(event, 'add'),
++ wx.ITEM_CHECK),
++ ('remove', icons['editCatRemove'],
++ lambda event: self.SetPloltsMode(event, 'remove'),
++ wx.ITEM_CHECK),
++ (None, ),
++ ('add_scatt', icons["add_scatt_pl"],
++ lambda event : self.scatt_mgr.AddScattPlot())
++ #('settings', icon["settings"],
++ # self.parent.OnSettings),
++ #('help', icons["help"],
++ # self.OnHelp),
++ ))
++
++ def GetToolId(self, toolName): #TODO can be useful in base
++
++ return vars(self)[toolName]
++
++ def SetPloltsMode(self, event, tool_name):
++
++ #TODO move to toolbars
++ if event.Checked() == True:
++ for i_tool_data in self._data:
++ i_tool_name = i_tool_data[0]
++ if not i_tool_name or i_tool_name == "cats_mgr":
++ continue
++ if i_tool_name == tool_name:
++ continue
++ i_tool_id = vars(self)[i_tool_name]
++
++ self.ToggleTool(i_tool_id, False)
++ self.scatt_mgr.SetPlotsMode(mode = tool_name)
++ return
++
++ self.scatt_mgr.SetPlotsMode(mode = None)
+\ No newline at end of file
+Index: gui/wxpython/scatt_plot/toolbars.py
+===================================================================
+--- gui/wxpython/scatt_plot/toolbars.py (revision 0)
++++ gui/wxpython/scatt_plot/toolbars.py (working copy)
+@@ -0,0 +1,106 @@
++"""!
++ at package scatt_plot.toolbars
++
++ at brief Scatter plot - toolbars
++
++Classes:
++ - toolbars::MainToolbar
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++
++
++import wx
++
++from icons.icon import MetaIcon
++from gui_core.toolbars import BaseToolbar, BaseIcons
++from core.gcmd import RunCommand
++
++class MainToolbar(BaseToolbar):
++ """!Main toolbar
++ """
++ def __init__(self, parent):
++ BaseToolbar.__init__(self, parent)
++
++ self.InitToolbar(self._toolbarData())
++
++ # realize the toolbar
++ self.Realize()
++
++ def _toolbarData(self):
++
++ icons = {
++ 'set_data' : MetaIcon(img = 'layer-raster-add',
++ label = _('Set input raster data for plots')),
++ 'settings' : BaseIcons['settings'].SetLabel( _('Ssettings')),
++ 'help' : MetaIcon(img = 'help',
++ label = _('Show manual')),
++ 'add_scatt_pl' : MetaIcon(img = 'layer-raster-analyze',
++ label = _('Add scatter plot'))
++ }
++
++ return self._getToolbarData((
++ ('sat_data', icons["set_data"],
++ self.parent.OnSetData),
++ (None, ),
++ ('add_scatt', icons["add_scatt_pl"],
++ self.parent.OnAddScattPl),
++ #('settings', icons["settings"],
++ # self.parent.OnSettings),
++ #('help', icons["help"],
++ # self.OnHelp),
++ ("quit", BaseIcons['quit'],
++ self.parent.OnCloseDialog)
++ ))
++
++ def OnHelp(self, event) :
++ RunCommand('g.manual',
++ entry = 'wxGUI.scatt_plot')
++
++class CategoriesToolbar(BaseToolbar):
++
++ def __init__(self, parent, cats_list, scatts_dlg):
++ BaseToolbar.__init__(self, parent)
++ self.cats_list = cats_list
++ self.scatts_dlg = scatts_dlg
++
++ self.InitToolbar(self._toolbarData())
++
++
++ # realize the toolbar
++ self.Realize()
++
++
++ def _toolbarData(self):
++
++ icons = {
++ 'editCatAdd' : MetaIcon(img = 'polygon-create',
++ label = _('Add region to category mode')),
++ 'editCatRemove' : MetaIcon(img = 'polygon-delete',
++ label = _('Remove region to category mode')),
++ 'addCat' : MetaIcon(img = 'layer-add',
++ label = _('Add category')),
++ 'deleteCat' : MetaIcon(img = 'layer-remove',
++ label = _('Delete category'))
++ }
++
++ return self._getToolbarData((('editCatAdd', icons['editCatAdd'],
++ lambda event: self.scatts_dlg.EditCatAdd(),
++ wx.ITEM_CHECK),
++ ('editCatRemove', icons['editCatRemove'],
++ lambda event: self.scatts_dlg.EditCatRemove(),
++ wx.ITEM_CHECK),
++ (None, ),
++ ('addCat', icons["addCat"],
++ lambda event: self.cats_list.AddCategory()),
++ ('deleteCat', icons["deleteCat"],
++ lambda event: self.cats_list.DeleteCategory())))
++
++ def GetToolId(self, toolName): #TODO can be useful in base
++
++ return vars(self)[toolName]
+\ No newline at end of file
+Index: gui/wxpython/mapdisp/toolbars.py
+===================================================================
+--- gui/wxpython/mapdisp/toolbars.py (revision 57453)
++++ gui/wxpython/mapdisp/toolbars.py (working copy)
+@@ -239,7 +239,8 @@
+ (MapIcons["scatter"], self.parent.OnScatterplot),
+ (MapIcons["histogram"], self.parent.OnHistogramPyPlot),
+ (BaseIcons["histogramD"], self.parent.OnHistogram),
+- (MapIcons["vnet"], self.parent.OnVNet)))
++ (MapIcons["vnet"], self.parent.OnVNet),
++ (MapIcons["scatter"], self.parent.OnScatterplot2)))
-+ self.editingStarted.emit(vectMap = mapLayer.GetName(), digit = self.digit)
- return True
+ def OnDecoration(self, event):
+ """!Decorations overlay menu
+Index: gui/wxpython/mapdisp/frame.py
+===================================================================
+--- gui/wxpython/mapdisp/frame.py (revision 57453)
++++ gui/wxpython/mapdisp/frame.py (working copy)
+@@ -225,6 +225,7 @@
+ #
+ self.dialogs = {}
+ self.dialogs['attributes'] = None
++ self.dialogs['scatt_plot'] = None
+ self.dialogs['category'] = None
+ self.dialogs['barscale'] = None
+ self.dialogs['legend'] = None
+@@ -1168,6 +1169,19 @@
+ """!Returns toolbar with zooming tools"""
+ return self.toolbars['map']
- def StopEditing(self):
++ def OnScatterplot2(self, event):
++ """!Init interactive scatterplot tools
++ """
++ if self.dialogs['scatt_plot']:
++ self.dialogs['scatt_plot'].Raise()
++ return
++
++ from scatt_plot.dialogs import ScattPlotMainDialog
++ self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface)
++
++ self.dialogs['scatt_plot'].CenterOnScreen()
++ self.dialogs['scatt_plot'].Show()
++
+ def OnVNet(self, event):
+ """!Dialog for v.net* modules
+ """
Index: gui/wxpython/vdigit/wxdigit.py
===================================================================
---- gui/wxpython/vdigit/wxdigit.py (revision 57437)
+--- gui/wxpython/vdigit/wxdigit.py (revision 57453)
+++ gui/wxpython/vdigit/wxdigit.py (working copy)
@@ -17,7 +17,7 @@
(and NumPy would be an excellent candidate for acceleration via
@@ -3178,7 +2784,7 @@
"""!Delete selected features
@@ -434,16 +451,27 @@
- # colect categories for delete if requested
+ # collect categories for deleting if requested
deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
catDict = dict()
+
@@ -3210,7 +2816,7 @@
poList = self._display.GetSelectedIList()
nlines = Vedit_delete_lines(self.poMapInfo, poList)
@@ -456,7 +484,8 @@
- self._deleteRecords(cats)
+ self._deleteRecords(catDict)
self._addChangeset()
self.toolbar.EnableUndo()
-
@@ -3543,7 +3149,7 @@
return newline
def FlipLine(self):
-@@ -1510,26 +1753,52 @@
+@@ -1514,26 +1757,52 @@
return 0
poList = self._display.GetSelectedIList()
@@ -3598,57 +3204,374 @@
return 1
def GetLineCats(self, line):
-Index: gui/wxpython/mapdisp/toolbars.py
+Index: gui/wxpython/vdigit/toolbars.py
===================================================================
---- gui/wxpython/mapdisp/toolbars.py (revision 57437)
-+++ gui/wxpython/mapdisp/toolbars.py (working copy)
-@@ -239,7 +239,8 @@
- (MapIcons["scatter"], self.parent.OnScatterplot),
- (MapIcons["histogram"], self.parent.OnHistogramPyPlot),
- (BaseIcons["histogramD"], self.parent.OnHistogram),
-- (MapIcons["vnet"], self.parent.OnVNet)))
-+ (MapIcons["vnet"], self.parent.OnVNet),
-+ (MapIcons["scatter"], self.parent.OnScatterplot2)))
+--- gui/wxpython/vdigit/toolbars.py (revision 57453)
++++ gui/wxpython/vdigit/toolbars.py (working copy)
+@@ -17,6 +17,7 @@
+ import wx
+
+ from grass.script import core as grass
++from grass.pydispatch.signal import Signal
+
+ from gui_core.toolbars import BaseToolbar, BaseIcons
+ from gui_core.dialogs import CreateNewVector
+@@ -42,6 +43,8 @@
+ self.digit = None
+ self._giface = giface
- def OnDecoration(self, event):
- """!Decorations overlay menu
-Index: gui/wxpython/mapdisp/frame.py
++ self.editingStarted = Signal("VDigitToolbar.editingStarted")
++
+ # currently selected map layer for editing (reference to MapLayer instance)
+ self.mapLayer = None
+ # list of vector layers from Layer Manager (only in the current mapset)
+@@ -860,6 +863,7 @@
+ alpha = int(opacity * 255)
+ self.digit.GetDisplay().UpdateSettings(alpha = alpha)
+
++ self.editingStarted.emit(vectMap = mapLayer.GetName(), digit = self.digit)
+ return True
+
+ def StopEditing(self):
+Index: gui/wxpython/Makefile
===================================================================
---- gui/wxpython/mapdisp/frame.py (revision 57437)
-+++ gui/wxpython/mapdisp/frame.py (working copy)
-@@ -226,6 +226,7 @@
+--- gui/wxpython/Makefile (revision 57453)
++++ gui/wxpython/Makefile (working copy)
+@@ -13,7 +13,7 @@
+ $(wildcard animation/* core/*.py dbmgr/* gcp/*.py gmodeler/* \
+ gui_core/*.py iclass/* lmgr/*.py location_wizard/*.py mapwin/*.py mapdisp/*.py \
+ mapswipe/* modules/*.py nviz/*.py psmap/* rlisetup/* vdigit/* \
+- vnet/*.py web_services/*.py wxplot/*.py) \
++ vnet/*.py web_services/*.py wxplot/*.py scatt_plot/*.py) \
+ gis_set.py gis_set_error.py wxgui.py README
+
+ DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES)) \
+@@ -21,7 +21,7 @@
+
+ PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,animation core dbmgr gcp gmodeler \
+ gui_core iclass lmgr location_wizard mapwin mapdisp modules nviz psmap \
+- mapswipe vdigit wxplot web_services rlisetup vnet)
++ mapswipe vdigit wxplot web_services rlisetup vnet scatt_plot)
+
+ DSTDIRS := $(patsubst %,$(ETCDIR)/%,icons scripts xml)
+
+Index: gui/wxpython/iclass/dialogs.py
+===================================================================
+--- gui/wxpython/iclass/dialogs.py (revision 57453)
++++ gui/wxpython/iclass/dialogs.py (working copy)
+@@ -333,13 +333,19 @@
+ toolbar.SetCategories(catNames = catNames, catIdx = cats)
+ if name in catNames:
+ toolbar.choice.SetStringSelection(name)
++ cat = toolbar.GetSelectedCategoryIdx()
+ elif catNames:
+ toolbar.choice.SetSelection(0)
+-
++ cat = toolbar.GetSelectedCategoryIdx()
++ else:
++ cat = None
++
+ if toolbar.choice.IsEmpty():
+ toolbar.EnableControls(False)
+ else:
+ toolbar.EnableControls(True)
++
++ self.mapWindow.CategoryChanged(cat)
+ # don't forget to update maps, histo, ...
+
+ def GetSelectedIndices(self, state = wx.LIST_STATE_SELECTED):
+Index: gui/wxpython/iclass/toolbars.py
+===================================================================
+--- gui/wxpython/iclass/toolbars.py (revision 57453)
++++ gui/wxpython/iclass/toolbars.py (working copy)
+@@ -46,9 +46,7 @@
+ 'importAreas' : MetaIcon(img = 'layer-import',
+ label = _('Import training areas from vector map')),
+ 'addRgb' : MetaIcon(img = 'layer-rgb-add',
+- label = _('Add RGB map layer')),
+- 'scatt_plot' : MetaIcon(img = 'layer-raster-analyze',
+- label = _('Open Scatter Plot Tool (EXPERIMENTAL GSoC 2013)')),
++ label = _('Add RGB map layer'))
+ }
+
+ class IClassMapToolbar(BaseToolbar):
+@@ -117,10 +115,7 @@
+ ("zoomBack", icons["zoomBack"],
+ self.parent.OnZoomBack),
+ ("zoomToMap", icons["zoomExtent"],
+- self.parent.OnZoomToMap),
+- (None, ),
+- ("scatt_plot", iClassIcons["scatt_plot"],
+- self.parent.OnScatterplot)
++ self.parent.OnZoomToMap)
+ ))
+ class IClassToolbar(BaseToolbar):
+ """!IClass toolbar
+@@ -156,7 +151,7 @@
+ """!Toolbar data"""
+ icons = iClassIcons
+ return self._getToolbarData((("selectGroup", icons['selectGroup'],
+- self.parent.OnAddBands),
++ lambda event : self.parent.AddBands()),
+ (None, ),
+ ("classManager", icons['classManager'],
+ self.parent.OnCategoryManager),
+Index: gui/wxpython/iclass/frame.py
+===================================================================
+--- gui/wxpython/iclass/frame.py (revision 57453)
++++ gui/wxpython/iclass/frame.py (working copy)
+@@ -64,6 +64,8 @@
+ IClassExportAreasDialog, IClassMapDialog
+ from iclass.plots import PlotPanel
+
++from grass.pydispatch.signal import Signal
++
+ class IClassMapFrame(DoubleMapFrame):
+ """! wxIClass main frame
+
+@@ -114,6 +116,10 @@
+ lambda:
+ self.statusbarManager.statusbarItems['coordinates'].SetAdditionalInfo(None))
+ self.SetSize(size)
++
++ self.groupSet = Signal("IClassMapFrame.groupSet")
++ self.categoryChanged = Signal('IClassMapFrame.categoryChanged')
++
#
- self.dialogs = {}
- self.dialogs['attributes'] = None
-+ self.dialogs['scatt_plot'] = None
- self.dialogs['category'] = None
- self.dialogs['barscale'] = None
- self.dialogs['legend'] = None
-@@ -1173,6 +1174,19 @@
- """!Returns toolbar with zooming tools"""
- return self.toolbars['map']
+ # Add toolbars
+ #
+@@ -177,7 +183,7 @@
+ self.dialogs['category'] = None
+
+ # PyPlot init
+- self.plotPanel = PlotPanel(self, stats_data = self.stats_data)
++ self.plotPanel = PlotPanel(self, giface = self._giface, stats_data = self.stats_data)
+
+ self._addPanes()
+ self._mgr.Update()
+@@ -237,7 +243,7 @@
+ return False
+
+ return vectorName
+-
++
+ def RemoveTempVector(self):
+ """!Removes temporary vector map with training areas"""
+ ret = RunCommand(prog = 'g.remove',
+@@ -477,7 +483,7 @@
+
+ self.Render(self.GetFirstWindow())
+
+- def OnAddBands(self, event):
++ def AddBands(self):
+ """!Add imagery group"""
+ dlg = IClassGroupDialog(self, group = self.group)
+ if dlg.ShowModal() == wx.ID_OK:
+@@ -488,7 +494,8 @@
+ """!Set imagery group"""
+ group = grass.find_file(name = name, element = 'group')
+ if group['name']:
+- self.group = group['name']
++ self.group = group['name']
++ self.groupSet.emit(group = group['name'])
+ else:
+ GError(_("Group <%s> not found") % name, parent = self)
+
+@@ -768,17 +775,20 @@
+
+ Updates number of stddev, histograms, layer in preview display.
+ """
+- stat = self.stats_data.GetStatistics(currentCat)
+- nstd = stat.nstd
+- self.toolbars['iClass'].UpdateStddev(nstd)
+-
+- self.plotPanel.UpdateCategory(currentCat)
+- self.plotPanel.OnPlotTypeSelected(None)
++ if currentCat:
++ stat = self.stats_data.GetStatistics(currentCat)
++ nstd = stat.nstd
++ self.toolbars['iClass'].UpdateStddev(nstd)
++
++ self.plotPanel.UpdateCategory(currentCat)
++ self.plotPanel.OnPlotTypeSelected(None)
+
+- name = stat.rasterName
+- name = self.previewMapManager.GetAlias(name)
+- if name:
+- self.previewMapManager.SelectLayer(name)
++ name = stat.rasterName
++ name = self.previewMapManager.GetAlias(name)
++ if name:
++ self.previewMapManager.SelectLayer(name)
++
++ self.categoryChanged.emit(cat = currentCat)
+
+ def DeleteAreas(self, cats):
+ """!Removes all training areas of given categories
+@@ -1105,27 +1115,6 @@
+ self.GetFirstWindow().SetModePointer()
+ self.GetSecondWindow().SetModePointer()
-+ def OnScatterplot2(self, event):
+- def OnScatterplot(self, event):
+- """!Init interactive scatterplot tools
+- """
+- if self.dialogs['scatt_plot']:
+- self.dialogs['scatt_plot'].Raise()
+- return
+-
+- try:
+- from scatt_plot.dialogs import ScattPlotMainDialog
+- except:
+- GError(parent = self, message = _("The Scatter Plot Tool is not installed."))
+- return
+-
+- self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface, iclass_mapwin = self.GetFirstWindow())
+-
+- scatt_mgr = self.dialogs['scatt_plot'].GetScattMgr()
+- scatt_mgr.DigitDataChanged(self.toolbars['vdigit'].mapLayer.GetName(), self.GetFirstWindow().GetDigit())
+-
+- self.dialogs['scatt_plot'].CenterOnScreen()
+- self.dialogs['scatt_plot'].Show()
+-
+ class MapManager:
+ """! Class for managing map renderer.
+
+Index: gui/wxpython/iclass/plots.py
+===================================================================
+--- gui/wxpython/iclass/plots.py (revision 57453)
++++ gui/wxpython/iclass/plots.py (working copy)
+@@ -28,7 +28,7 @@
+ for each band and for one category. Coincidence plots show min max range
+ of classes for each band.
+ """
+- def __init__(self, parent, stats_data):
++ def __init__(self, parent, giface, stats_data):
+ scrolled.ScrolledPanel.__init__(self, parent)
+
+ self.SetupScrolling(scroll_x = False, scroll_y = True)
+@@ -38,26 +38,62 @@
+ self.stats_data = stats_data
+ self.currentCat = None
+
++ self._giface = giface
++
+ self.mainSizer = wx.BoxSizer(wx.VERTICAL)
+-
++
+ self._createControlPanel()
+-
++ self._createPlotPanel()
++ self._createScatterPlotPanel()
++
+ self.SetSizer(self.mainSizer)
+ self.mainSizer.Fit(self)
+ self.Layout()
+
++ def _createPlotPanel(self):
++
++ self.canvasPanel = wx.Panel(parent=self)
++ self.mainSizer.Add(item = self.canvasPanel, proportion = 1, flag = wx.EXPAND, border = 0)
++ self.canvasSizer = wx.BoxSizer(wx.VERTICAL)
++ self.canvasPanel.SetSizer(self.canvasSizer)
++
+ def _createControlPanel(self):
+ self.plotSwitch = wx.Choice(self, id = wx.ID_ANY,
+ choices = [_("Histograms"),
+- _("Coincident plots")])
++ _("Coincident plots"),
++ _("Scatter plots")])
+ self.mainSizer.Add(self.plotSwitch, proportion = 0, flag = wx.EXPAND|wx.ALL, border = 5)
+ self.plotSwitch.Bind(wx.EVT_CHOICE, self.OnPlotTypeSelected)
+-
++
++ def _createScatterPlotPanel(self):
+ """!Init interactive scatterplot tools
+ """
-+ if self.dialogs['scatt_plot']:
-+ self.dialogs['scatt_plot'].Raise()
-+ return
++ try:
++ from scatt_plot.dialogs_iclass import IClassScatterPlotsPanel
++ self.scatt_plot_panel = IClassScatterPlotsPanel(parent=self, giface=self._giface, iclass_mapwin = self.parent.GetFirstWindow())
++ self.mainSizer.Add(self.scatt_plot_panel, proportion = 1, flag = wx.EXPAND, border = 0)
++ self.scatt_plot_panel.Hide()
++ except ImportError as e:
++ self.scatt_plot_panel = None
+
-+ from scatt_plot.dialogs import ScattPlotMainDialog
-+ self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface)
-+
-+ self.dialogs['scatt_plot'].CenterOnScreen()
-+ self.dialogs['scatt_plot'].Show()
+ def OnPlotTypeSelected(self, event):
+ """!Plot type selected"""
+
- def OnVNet(self, event):
- """!Dialog for v.net* modules
- """
++ if self.plotSwitch.GetSelection() in [0, 1]:
++ self.SetupScrolling(scroll_x = False, scroll_y = True)
++ self.scatt_plot_panel.Hide()
++ self.canvasPanel.Show()
++ self.Layout()
++
++ elif self.plotSwitch.GetSelection() == 2:
++ self.SetupScrolling(scroll_x = False, scroll_y = False)
++ self.scatt_plot_panel.Show()
++ self.canvasPanel.Hide()
++ self.Layout()
++
+ if self.currentCat is None:
+ return
+-
++
+ if self.plotSwitch.GetSelection() == 0:
+ stat = self.stats_data.GetStatistics(self.currentCat)
+ if not stat.IsReady():
+@@ -66,7 +102,10 @@
+ self.DrawHistograms(stat)
+ else:
+ self.DrawCoincidencePlots()
+-
++
++ self.Layout()
++
++
+ def StddevChanged(self):
+ """!Standard deviation multiplier changed, redraw histograms"""
+ if self.plotSwitch.GetSelection() == 0:
+@@ -89,7 +128,7 @@
+ panel.Destroy()
+
+ self.canvasList = []
+-
++
+ def ClearPlots(self):
+ """!Clears plot canvases"""
+ for bandIdx in range(len(self.bandList)):
+@@ -104,15 +143,15 @@
+ def CreatePlotCanvases(self):
+ """!Create plot canvases according to the number of bands"""
+ for band in self.bandList:
+- canvas = plot.PlotCanvas(self)
++ canvas = plot.PlotCanvas(self.canvasPanel)
+ canvas.SetMinSize((-1, 140))
+ canvas.SetFontSizeTitle(10)
+ canvas.SetFontSizeAxis(8)
+ self.canvasList.append(canvas)
+
+- self.mainSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
+-
+- self.SetVirtualSize(self.GetBestVirtualSize())
++ self.canvasSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
++
++ self.SetVirtualSize(self.GetBestVirtualSize())
+ self.Layout()
+
+ def UpdatePlots(self, group, currentCat, stats_data):
+@@ -138,7 +177,7 @@
+
+ def UpdateCategory(self, cat):
+ self.currentCat = cat
+-
++
+ def DrawCoincidencePlots(self):
+ """!Draw coincidence plots"""
+ for bandIdx in range(len(self.bandList)):
Index: lib/imagery/scatt_sccats.c
===================================================================
--- lib/imagery/scatt_sccats.c (revision 0)
+++ lib/imagery/scatt_sccats.c (working copy)
-@@ -0,0 +1,421 @@
+@@ -0,0 +1,405 @@
+/*!
+ \file lib/imagery/scatt_cat_rast.c
+
@@ -3674,42 +3597,58 @@
+/*!
+ \brief Compute band ids from scatter plot id.
+
++ Scatter plot id describes which bands defines the scatter plot.
++
++ Let say we have 3 bands, their ids are 0, 1 and 2.
++ Scatter plot with id 0 consists of band 1 (b_1_id) 0 and band 2 (b_2_id) 1.
++ All scatter plots:
++ scatt_id b_1_id b_2_id
++ 0 0 1
++ 1 0 2
++ 2 1 2
++
+ \param scatt_id scatter plot id
+ \param n_bands number of bands
-+ \param [out] band_1 id of band1
-+ \param[out] band_2 id of band2
++ \param [out] b_1_id id of band1
++ \param[out] b_2_id id of band2
++
++ \return 0
+ */
-+static void id_scatt_to_bands(const int scatt_id, const int n_bands, int * band_1, int * band_2)
++int I_id_scatt_to_bands(const int scatt_id, const int n_bands, int * b_1_id, int * b_2_id)
+{
+ int n_b1 = n_bands - 1;
+
-+ * band_1 = (int) ((2 * n_b1 + 1 - sqrt((double)((2 * n_b1 + 1) * (2 * n_b1 + 1) - 8 * scatt_id))) / 2);
++ * b_1_id = (int) ((2 * n_b1 + 1 - sqrt((double)((2 * n_b1 + 1) * (2 * n_b1 + 1) - 8 * scatt_id))) / 2);
+
-+ * band_2 = scatt_id - ((* band_1) * (2 * n_b1 + 1) - (* band_1) * (* band_1)) / 2 + (* band_1) + 1;
++ * b_2_id = scatt_id - ((* b_1_id) * (2 * n_b1 + 1) - (* b_1_id) * (* b_1_id)) / 2 + (* b_1_id) + 1;
+
-+ return;
++ return 0;
+}
+
+
+/*!
+ \brief Compute scatter plot id from band ids.
+
++ See also I_id_scatt_to_bands().
++
+ \param n_bands number of bands
-+ \param band_1 id of band1
-+ \param band_2 id of band2
++ \param b_1_id id of band1
++ \param b_1_id id of band2
+ \param [out] scatt_id scatter plot id
++
++ \return 0
+ */
-+static void bands_to_id_scatt(const int band_1, const int band_2, const int n_bands, int * scatt_id)
++int I_bands_to_id_scatt(const int b_1_id, const int b_2_id, const int n_bands, int * scatt_id)
+{
+ int n_b1 = n_bands - 1;
+
-+ * scatt_id = (band_1 * (2 * n_b1 + 1) - band_1 * band_1) / 2 + band_2 - band_1 - 1;
++ * scatt_id = (b_1_id * (2 * n_b1 + 1) - b_1_id * b_1_id) / 2 + b_2_id - b_1_id - 1;
+
-+ return;
++ return 0;
+}
+
+/*!
-+ \brief Initialize structury for soring scatter plots data.
++ \brief Initialize structure for storing scatter plots data.
+
+ \param cats pointer to scCats struct
+ \param n_bands number of bands
@@ -3741,7 +3680,7 @@
+}
+
+/*!
-+ \brief Free date of struct scCats, the structure itself remains alocated. .
++ \brief Free data of struct scCats, the structure itself remains alocated.
+
+ \param cats pointer to existing scCats struct
+ */
@@ -3774,40 +3713,37 @@
+}
+
+#if 0
-+
+void I_sc_get_active_categories(int * a_cats_ids, int * n_a_cats, struct scCats * cats)
+{
+ a_cats_ids = cats->cats_ids;
+ * n_a_cats = cats->n_a_cats;
+}
-+
+#endif
++
+/*!
+ \brief Add category.
+
+ Category represents group of scatter plots.
+
+ \param cats pointer to scCats struct
-+ \param cat_id number id of category.
+
-+ \return -2 value if id is over limit
-+ \return -1 category id is invalid
-+ \return 0 category was added
++ \return assigned category id (starts with 0)
++ \return -1 if maximum nuber of categories was reached
+ */
-+int I_sc_add_cat(struct scCats * cats, int cat_id)
++int I_sc_add_cat(struct scCats * cats)
+{
-+ int i_scatt;
++ int i_scatt, i_cat_id, cat_id;
+ int n_a_cats = cats->n_a_cats;
+
-+ if(cat_id < 0 || cat_id > cats->n_cats)
++ if(cats->n_a_cats >= cats->n_cats)
+ return -1;
+
-+ if(cat_id >= cats->n_cats)
-+ return -2;
++ for(i_cat_id = 0; i_cat_id < cats->n_cats; i_cat_id++)
++ if(cats->cats_idxs[i_cat_id] < 0) {
++ cat_id = i_cat_id;
++ break;
++ }
+
-+ if(cats->cats_idxs[cat_id] >= 0)
-+ return -1;
-+
+ cats->cats_ids[n_a_cats] = cat_id;
+ cats->cats_idxs[cat_id] = n_a_cats;
+
@@ -3826,7 +3762,7 @@
+
+ ++cats->n_a_cats;
+
-+ return 0;
++ return cat_id;
+}
+
+#if 0
@@ -3899,7 +3835,7 @@
+
+ scatts->scatt_idxs[scatt_id] = n_a_scatts;
+
-+ id_scatt_to_bands(scatt_id, cats->n_bands, &band_1, &band_2);
++ I_id_scatt_to_bands(scatt_id, cats->n_bands, &band_1, &band_2);
+
+ scatts->scatts_bands[n_a_scatts * 2] = band_1;
+ scatts->scatts_bands[n_a_scatts * 2 + 1] = band_2;
@@ -3970,31 +3906,17 @@
+#endif
+
+/*!
-+ \brief Insert scatter plot data .
++ \brief Insert scatter plot data.
+
+ \param scatt_data pointer to existing struct scdScattData
+ \param type SC_SCATT_DATA for scatter plots or SC_SCATT_CONDITIONS for selected areas in scatter plot
+ \param n_vals number of data values
+ \param data array of values (unsigned char for SC_SCATT_CONDITIONS, unsigned int for SC_SCATT_DATA)
-+ \param band_1_range data range of band1
-+ \param band_2_range data range of band2
-+
-+ \return 0 on success
-+ \return -1 on failure
+ */
-+void I_scd_init_scatt_data(struct scdScattData * scatt_data, int type, int n_vals, void * data,
-+ struct Range band_1_range, struct Range band_2_range)
++void I_scd_init_scatt_data(struct scdScattData * scatt_data, int type, int n_vals, void * data)
+{
+ scatt_data->n_vals = n_vals;
+
-+ scatt_data->band_1_range.min = band_1_range.min;
-+ scatt_data->band_1_range.max = band_1_range.max;
-+ scatt_data->band_1_range.first_time = 0;
-+
-+ scatt_data->band_2_range.min = band_2_range.min;
-+ scatt_data->band_2_range.max = band_2_range.max;
-+ scatt_data->band_2_range.first_time = 0;
-+
+ if(type == SC_SCATT_DATA)
+ {
+ if(data)
@@ -4019,22 +3941,7 @@
+ return;
+}
+
-+/*!
-+ \brief Free members of scdScattData struct.
+
-+ \param scatt_data struct scdScattData to be freed
-+ */
-+void I_scd_free_scatt_data(struct scdScattData * scatt_data)
-+{
-+
-+ G_free(scatt_data->b_conds_arr);
-+ G_free(scatt_data->scatt_vals_arr);
-+
-+ scatt_data = NULL;
-+
-+ return;
-+}
-+
+#if 0
+void I_scd_get_range_min_max(struct scdScattData * scatt_data, CELL * band_1_min, CELL * band_1_max, CELL * band_2_min, CELL * band_2_max)
+{
@@ -4074,7 +3981,7 @@
===================================================================
--- lib/imagery/scatt.c (revision 0)
+++ lib/imagery/scatt.c (working copy)
-@@ -0,0 +1,696 @@
+@@ -0,0 +1,745 @@
+/*!
+ \file lib/imagery/scatt.c
+
@@ -4093,6 +4000,7 @@
+#include <grass/raster.h>
+#include <grass/imagery.h>
+#include <grass/gis.h>
++#include <grass/glocale.h>
+
+#include <stdio.h>
+#include <stdlib.h>
@@ -4100,23 +4008,30 @@
+#include <string.h>
+
+
++struct rast_row
++{
++ CELL * row;
++ char * null_row;
++ struct Range rast_range; /*Range of whole raster.*/
++};
++
+/*!
+ \brief Create pgm header.
+
-+ Scatter plot internally generates pgm files. These pns has header in format created by this function.
++ Scatter plot internally generates pgm files. These pgms have header in format created by this function.
+
-+ \param region - region to be pgm header generated for
-+ \param [out] header - header pgm
++ \param region region to be pgm header generated for
++ \param [out] header header of pgm file
+ */
+static int get_cat_rast_header(struct Cell_head * region, char * header){
+ return sprintf(header, "P5\n%d\n%d\n1\n", region->cols, region->rows);
+}
+
+/*!
-+ \brief Create pgm file.
-+
-+ \param cat_rast_region - region to be file generated for
-+ \param cat_rast - path of pgm file
++ \brief Create category raster conditions file.
++
++ \param cat_rast_region region to be file generated for
++ \param cat_rast path of generated category raster file
+ */
+int I_create_cat_rast(struct Cell_head * cat_rast_region, const char * cat_rast)
+{
@@ -4128,14 +4043,17 @@
+ unsigned char * row_data;
+
+ f_cat_rast = fopen(cat_rast, "wb");
-+ if(!f_cat_rast)
++ if(!f_cat_rast) {
++ G_warning("Unable to create category raster condition file <%s>.", cat_rast);
+ return -1;
++ }
+
+ head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
+
+ fwrite(cat_rast_header, sizeof(char), head_nchars/sizeof(char), f_cat_rast);
+ if (ferror(f_cat_rast)){
+ fclose(f_cat_rast);
++ G_warning(_("Unable to write header into category raster condition file <%s>."), cat_rast);
+ return -1;
+ }
+
@@ -4148,7 +4066,7 @@
+ if (ferror(f_cat_rast))
+ {
+ fclose(f_cat_rast);
-+ G_debug(3, "Unable to write into file.");
++ G_warning(_("Unable to write into category raster condition file <%s>."), cat_rast);
+ return -1;
+ }
+ }
@@ -4157,9 +4075,9 @@
+ return 0;
+}
+
-+static int print_reg(struct Cell_head * intersec, const char * pref)
++static int print_reg(struct Cell_head * intersec, const char * pref, int dbg_level)
+{
-+ G_debug(0, "%s:\n n:%f\ns:%f\ne:%f\nw:%f\nns_res:%f\new_res:%f", pref, intersec->north, intersec->south,
++ G_debug(dbg_level, "%s:\n n:%f\ns:%f\ne:%f\nw:%f\nns_res:%f\new_res:%f", pref, intersec->north, intersec->south,
+ intersec->east, intersec->west, intersec->ns_res, intersec->ew_res);
+}
+
@@ -4168,7 +4086,7 @@
+
+ \param A pointer to intersected region
+ \param B pointer to intersected region
-+ \param [out] intersec pointer to intersection region of regions A B ( valid params of the region are: south, north, east, west)
++ \param [out] intersec pointer to intersection region of regions A B (relevant params of the region are: south, north, east, west)
+
+ \return 0 if interection exists
+ \return -1 if regions does not intersect
@@ -4204,12 +4122,13 @@
+ \brief Get rows and cols numbers, which defines intersection of the regions.
+
+ \param A pointer to intersected region
-+ \param B pointer to intersected region
++ \param B pointer to intersected region (A and B must have same resolution)
+ \param [out] A_bounds rows and cols numbers of A stored in south, north, east, west, which defines intersection of A and B
-+ \param [out] A_bounds rows and cols numbers of B stored in south, north, east, west, which defines intersection of A and B
++ \param [out] B_bounds rows and cols numbers of B stored in south, north, east, west, which defines intersection of A and B
+
+ \return 0 if interection exists
+ \return -1 if regions do not intersect
++ \return -2 resolution of regions is not same
+*/
+static int get_rows_and_cols_bounds(struct Cell_head * A, struct Cell_head * B, struct Cell_head * A_bounds, struct Cell_head * B_bounds)
+{
@@ -4219,13 +4138,13 @@
+
+ /* TODO is it right check? */
+ if(abs(A->ns_res - B->ns_res) > GRASS_EPSILON) {
-+ G_debug(0, "'get_rows_and_cols_bounds' ns_res does not fit diff: %.20f", A->ew_res - B->ew_res);
-+ return -1;
++ G_debug(0, "'get_rows_and_cols_bounds' ns_res does not fit, A->ns_res: %f B->ns_res: %f", A->ns_res, B->ns_res);
++ return -2;
+ }
+
+ if(abs(A->ew_res - B->ew_res) > GRASS_EPSILON) {
-+ G_debug(0, "'get_rows_and_cols_bounds' ew_res does not fit diff: %.20f", A->ew_res - B->ew_res);
-+ return -1;
++ G_debug(0, "'get_rows_and_cols_bounds' ew_res does not fit, A->ew_res: %f B->ew_res: %f", A->ew_res, B->ew_res);
++ return -2;
+ }
+
+ ns_res = A->ns_res;
@@ -4253,8 +4172,8 @@
+ \brief Insert raster map patch into pgm file.
+
+ \param patch_rast name of raster map
-+ \param cat_rast_region region of pgm file
-+ \param cat_rast path to pgm file
++ \param cat_rast_region region of category raster file
++ \param cat_rast path to category raster file
+
+ \return 0 on success
+ \return -1 on failure
@@ -4266,13 +4185,12 @@
+ struct Cell_head patch_region, patch_bounds, cat_rast_bounds;
+ char cat_rast_header[1024];//TODO magic number
+ int i_row, i_col, ncols, nrows, cat_rast_col, patch_col, val;
-+ int head_nchars;
++ int head_nchars, ret;
+ int fd_patch_rast, init_shift, step_shift;
+ unsigned char * patch_data;
+
+ char * null_chunk_row;
+
-+ //TODO G_free mapset (also in compute scatts)
+ const char *mapset;
+
+ struct Cell_head patch_lines, cat_rast_lines;
@@ -4280,14 +4198,15 @@
+ unsigned char * row_data;
+
+ f_cat_rast = fopen(cat_rast, "rb+");
-+ if(!f_cat_rast)
++ if(!f_cat_rast) {
++ G_warning(_("Unable to open category raster condtions file <%s>."), cat_rast);
+ return -1;
-+
-+ /* TODO */
-+ head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
++ }
+
-+ if ((mapset = G_find_raster2(patch_rast,"")) == NULL) {
++ head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
++ if ((mapset = G_find_raster(patch_rast,"")) == NULL) {
+ fclose(f_cat_rast);
++ G_warning(_("Unable to find patch raster <%s>."), patch_rast);
+ return -1;
+ }
+
@@ -4299,10 +4218,23 @@
+ return -1;
+ }
+
-+ null_chunk_row = Rast_allocate_null_buf();
++ ret = get_rows_and_cols_bounds(cat_rast_region, &patch_region, &cat_rast_bounds, &patch_bounds);
++ if(ret == -2) {
++ G_warning(_("Resolutions of patch <%s> and patched file <%s> are not same."), patch_rast, cat_rast);
+
-+ if(get_rows_and_cols_bounds(cat_rast_region, &patch_region, &cat_rast_bounds, &patch_bounds) == -1) return -1;
++ Rast_close(fd_patch_rast);
++ fclose(f_cat_rast);
+
++ return -1;
++ }
++ else if (ret == -1){
++
++ Rast_close(fd_patch_rast);
++ fclose(f_cat_rast);
++
++ return 0;
++ }
++
+ ncols = cat_rast_bounds.east - cat_rast_bounds.west;
+ nrows = cat_rast_bounds.south - cat_rast_bounds.north;
+
@@ -4311,11 +4243,18 @@
+ init_shift = head_nchars + cat_rast_region->cols * cat_rast_bounds.north + cat_rast_bounds.west;
+
+ if(fseek(f_cat_rast, init_shift, SEEK_SET) != 0) {
-+ G_message("seek failed");
++ G_warning(_("Corrupted category raster conditions file <%s> (fseek failed)"), cat_rast);
++
++ Rast_close(fd_patch_rast);
++ G_free(null_chunk_row);
++ fclose(f_cat_rast);
++
+ return -1;
+ }
+
+ step_shift = cat_rast_region->cols - ncols;
++
++ null_chunk_row = Rast_allocate_null_buf();
+
+ for(i_row = 0; i_row < nrows; i_row++) {
+ Rast_get_null_value_row (fd_patch_rast, null_chunk_row, i_row + patch_bounds.north);
@@ -4333,12 +4272,21 @@
+ fwrite(patch_data, sizeof(unsigned char), (ncols)/sizeof(unsigned char), f_cat_rast);
+ if (ferror(f_cat_rast))
+ {
++ G_warning(_("Unable to write into category raster conditions file <%s>"), cat_rast);
++
++ Rast_close(fd_patch_rast);
+ G_free(null_chunk_row);
+ fclose(f_cat_rast);
++
+ return -1;
+ }
+ if(fseek(f_cat_rast, step_shift, SEEK_CUR) != 0) {
-+ G_message("seek failed");
++ G_warning(_("Corrupted category raster conditions file <%s> (fseek failed)"), cat_rast);
++
++ Rast_close(fd_patch_rast);
++ G_free(null_chunk_row);
++ fclose(f_cat_rast);
++
+ return -1;
+ }
+ }
@@ -4352,52 +4300,60 @@
+/*!
+ \brief Updates scatter plots data in category by pixels which meets category conditions.
+
-+ \param chunk_rows data arrays of chunk_rows from analyzed raster bands (all data in chunk_rows, null_chunk_rows and belongs_pix arrays represents same region)
-+ \param null_chunk_rows null data arrays of chunk_rows from analyzed raster bands
-+ \param chunk_row_size size of data in chunk_rows, null_chunk_rows and belongs_pix arrays
++ \param bands_rows data represents data describig one row from raster band
+ \param belongs_pix array which defines which pixels belongs to category (1 value) and which not (0 value)
-+ \param scatts pointer to scScatts struct of type SC_SCATT_DATA, where are computed scatter plots stored
++ \param [out] scatts pointer to scScatts struct of type SC_SCATT_DATA, which are modified according to values in belongs_pix
+*/
-+static inline void update_cat_scatt_plts(CELL ** chunk_rows, char ** null_chunk_rows, int chunk_row_size, unsigned short * belongs_pix, struct scScatts * scatts)
++static inline void update_cat_scatt_plts(struct rast_row * bands_rows, unsigned short * belongs_pix, struct scScatts * scatts)
+{
+ int band_axis_1, band_axis_2, i_scatt, array_idx, cat_idx, i_chunk_rows_pix, max_arr_idx;
+
-+ CELL * b_1_chunk_rows;
-+ CELL * b_2_chunk_rows;
-+ char * band_1_null_chunk_rows,* band_2_null_chunk_rows;
++ CELL * b_1_row;
++ CELL * b_2_row;
++ char * b_1_null_row,* b_2_null_row;
++ struct rast_row b_1_rast_row, b_2_rast_row;
+
+ struct Range b_1_range, b_2_range;
+ int b_1_range_size;
+
++ int row_size = Rast_window_cols();
++
+ int * scatts_bands = scatts->scatts_bands;
+
+ for(i_scatt = 0; i_scatt < scatts->n_a_scatts; i_scatt++)
+ {
-+ b_1_chunk_rows = chunk_rows[scatts_bands[i_scatt * 2]];
-+ b_2_chunk_rows = chunk_rows[scatts_bands[i_scatt * 2 + 1]];
++ b_1_rast_row = bands_rows[scatts_bands[i_scatt * 2]];
++ b_2_rast_row = bands_rows[scatts_bands[i_scatt * 2 + 1]];
+
-+ band_1_null_chunk_rows = null_chunk_rows[scatts_bands[i_scatt * 2]];
-+ band_2_null_chunk_rows = null_chunk_rows[scatts_bands[i_scatt * 2 + 1]];
++ b_1_row = b_1_rast_row.row;
++ b_2_row = b_2_rast_row.row;
+
-+ b_1_range = scatts->scatts_arr[i_scatt]->band_1_range;
-+ b_2_range = scatts->scatts_arr[i_scatt]->band_2_range;
++ b_1_null_row = b_1_rast_row.null_row;
++ b_2_null_row = b_2_rast_row.null_row;
+
++ b_1_range = b_1_rast_row.rast_range;
++ b_2_range = b_2_rast_row.rast_range;
++
+ b_1_range_size = b_1_range.max - b_1_range.min + 1;
+ max_arr_idx = (b_1_range.max - b_1_range.min + 1) * (b_2_range.max - b_2_range.min + 1);
+
-+ for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
++ for(i_chunk_rows_pix = 0; i_chunk_rows_pix < row_size; i_chunk_rows_pix++)
+ {
++ /* pixel does not belongs to scatter plot or has null value in one of the bands */
+ if(!belongs_pix[i_chunk_rows_pix] ||
-+ band_1_null_chunk_rows[i_chunk_rows_pix] == 1 ||
-+ band_2_null_chunk_rows[i_chunk_rows_pix] == 1)
++ b_1_null_row[i_chunk_rows_pix] == 1 ||
++ b_2_null_row[i_chunk_rows_pix] == 1)
+ continue;
+
-+ array_idx = b_1_chunk_rows[i_chunk_rows_pix] - b_1_range.min + (b_2_chunk_rows[i_chunk_rows_pix] - b_2_range.min) * b_1_range_size;
++ /* index in scatter plot array */
++ array_idx = b_1_row[i_chunk_rows_pix] - b_1_range.min + (b_2_row[i_chunk_rows_pix] - b_2_range.min) * b_1_range_size;
+
+ if(array_idx < 0 || array_idx >= max_arr_idx) {
-+ G_warning ("pixel out of range");
++ G_warning ("Data inconsistent. Value computed for scatter plot is out of initialized range.");
+ continue;
+ }
++
++ /* increment scatter plot value */
+ ++scatts->scatts_arr[i_scatt]->scatt_vals_arr[array_idx];
+ }
+ }
@@ -4411,26 +4367,27 @@
+
+ \param chunk_rows data arrays of chunk_rows from analyzed raster bands (all data in chunk_rows, null_chunk_rows and belongs_pix arrays represents same region)
+ \param null_chunk_rows null data arrays of chunk_rows from analyzed raster bands
-+ \param chunk_row_size size of data in chunk_rows, null_chunk_rows and belongs_pix arrays
-+ \param f_cats_rasts_conds pgm file which stores selected areas (conditions) from mapwindow
++ \param row_size size of data in chunk_rows, null_chunk_rows and belongs_pix arrays
++ \param f_cats_rasts_conds file which stores selected areas (conditions) from mapwindow see I_create_cat_rast() and I_pa
+ \param fd_cats_rasts array of openedraster maps which represents all selected pixels for category
+ \param region analysis region
+
+ \return 0 on success
+ \return -1 on failure
+*/
-+static inline int compute_scatts_from_chunk_row(struct scCats * scatts, struct scCats * scatt_conds,
-+ CELL ** chunk_rows, char ** null_chunk_rows, int chunk_row_size, FILE ** f_cats_rasts_conds,
-+ int * fd_cats_rasts, struct Cell_head *region)
++static inline int compute_scatts_from_chunk_row(struct Cell_head *region, struct scCats * scatt_conds,
++ FILE ** f_cats_rasts_conds, struct rast_row * bands_rows,
++ struct scCats * scatts, int * fd_cats_rasts)
+{
+
-+ int i_chunk_rows_pix, i_cat, i_scatt, n_a_scatts, i_cond;
++ int i_rows_pix, i_cat, i_scatt, n_a_scatts, n_pixs;
+ int cat_id, scatt_plts_cat_idx, array_idx, max_arr_idx;
-+ char * band_1_null_chunk_rows,* band_2_null_chunk_rows;
++ char * b_1_null_row,* b_2_null_row;
++ struct rast_row b_1_rast_row, b_2_rast_row;
+ CELL * cat_rast_row;
+
+ struct scScatts * scatts_conds;
-+ struct scScatts * scatt_plts_scatts;
++ struct scScatts * scatts_scatt_plts;
+ struct scdScattData * conds;
+
+ struct Range b_1_range, b_2_range;
@@ -4439,14 +4396,17 @@
+ int * scatts_bands;
+ struct scdScattData ** scatts_arr;
+
-+ CELL * b_1_chunk_rows;
-+ CELL * b_2_chunk_rows;
++ CELL * b_1_row;
++ CELL * b_2_row;
+ unsigned char * i_scatt_conds;
+
-+ unsigned short * belongs_pix = (unsigned short *) G_malloc(chunk_row_size * sizeof(unsigned short));
-+ unsigned char * rast_pixs = (unsigned char *) G_malloc(chunk_row_size * sizeof(unsigned char));
++ int row_size = Rast_window_cols();
++
++ unsigned short * belongs_pix = (unsigned short *) G_malloc(row_size * sizeof(unsigned short));
++ unsigned char * rast_pixs = (unsigned char *) G_malloc(row_size * sizeof(unsigned char));
+ cat_rast_row = Rast_allocate_c_buf();
+
++
+ for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
+ {
+ scatts_conds = scatt_conds->cats_arr[i_cat];
@@ -4456,87 +4416,102 @@
+ scatt_plts_cat_idx = scatts->cats_idxs[cat_id];
+ if(scatt_plts_cat_idx < 0)
+ continue;
++ scatts_scatt_plts = scatts->cats_arr[scatt_plts_cat_idx];
+
-+ scatt_plts_scatts = scatts->cats_arr[scatt_plts_cat_idx];
++ G_zero(belongs_pix, row_size * sizeof(unsigned short));
+
-+ G_zero(belongs_pix, chunk_row_size * sizeof(unsigned short));
-+
++ /* if category has no conditions defined, scatter plots without any constraint are computed (default scatter plots) */
+ if(!scatts_conds->n_a_scatts && !f_cats_rasts_conds[i_cat]) {
-+ for(i_scatt = 0; i_scatt < scatt_plts_scatts->n_a_scatts; i_scatt++)
++ for(i_scatt = 0; i_scatt < scatts_scatt_plts->n_a_scatts; i_scatt++)
+ {
-+ for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
-+ belongs_pix[i_chunk_rows_pix] = 1;
++ /* all pixels belongs */
++ for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)
++ belongs_pix[i_rows_pix] = 1;
+ }
+ }
++ /* compute belonging pixels for defined conditions */
+ else
+ {
+ scatts_bands = scatts_conds->scatts_bands;
+
-+ if(f_cats_rasts_conds[i_cat])
-+
-+ fread(rast_pixs, sizeof(unsigned char), (chunk_row_size)/sizeof(unsigned char), f_cats_rasts_conds[i_cat]);
++ /* check conditions from category raster condtitions file */
++ if(f_cats_rasts_conds[i_cat]) {
++ n_pixs = fread(rast_pixs, sizeof(unsigned char), (row_size)/sizeof(unsigned char), f_cats_rasts_conds[i_cat]);
+ if (ferror(f_cats_rasts_conds[i_cat]))
+ {
+ G_free(rast_pixs);
+ G_free(belongs_pix);
-+ G_message("Unable to read from file.");
++ G_warning(_("Unable to read from category raster condtition file."));
+ return -1;
+ }
-+ for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
++ if (n_pixs != n_pixs) {
++ G_free(rast_pixs);
++ G_free(belongs_pix);
++ G_warning(_("Invalid size of category raster conditions file."));
++ return -1;
++
++ }
++
++ for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)
+ {
-+ if(rast_pixs[i_chunk_rows_pix] != 0 & 255)
-+ belongs_pix[i_chunk_rows_pix] = 1;
++ if(rast_pixs[i_rows_pix] != 0 & 255)
++ belongs_pix[i_rows_pix] = 1;
+ }
++ }
+
-+ // test every defined conditions in scatter plots
++ /* check condtions defined in scatter plots*/
+ for(i_scatt = 0; i_scatt < scatts_conds->n_a_scatts; i_scatt++)
+ {
-+ b_1_chunk_rows = chunk_rows[scatts_bands[i_scatt * 2]];
-+ b_2_chunk_rows = chunk_rows[scatts_bands[i_scatt * 2 + 1]];
++ b_1_rast_row = bands_rows[scatts_bands[i_scatt * 2]];
++ b_2_rast_row = bands_rows[scatts_bands[i_scatt * 2 + 1]];
+
-+ band_1_null_chunk_rows = null_chunk_rows[scatts_bands[i_scatt * 2]];
-+ band_2_null_chunk_rows = null_chunk_rows[scatts_bands[i_scatt * 2 + 1]];
++ b_1_row = b_1_rast_row.row;
++ b_2_row = b_2_rast_row.row;
+
-+ i_scatt_conds = scatts_conds->scatts_arr[i_scatt]->b_conds_arr;
++ b_1_null_row = b_1_rast_row.null_row;
++ b_2_null_row = b_2_rast_row.null_row;
+
-+ b_1_range = scatts_conds->scatts_arr[i_scatt]->band_1_range;
-+ b_2_range = scatts_conds->scatts_arr[i_scatt]->band_2_range;
++ b_1_range = b_1_rast_row.rast_range;
++ b_2_range = b_2_rast_row.rast_range;
+
+ b_1_range_size = b_1_range.max - b_1_range.min + 1;
-+
+ max_arr_idx = (b_1_range.max - b_1_range.min + 1) * (b_2_range.max - b_2_range.min + 1);
-+ //G_message("max_arr_idx scatt_conds: %d", max_arr_idx);
+
-+ for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
++ i_scatt_conds = scatts_conds->scatts_arr[i_scatt]->b_conds_arr;
++
++ for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)
+ {
-+ if(belongs_pix[i_chunk_rows_pix] ||
-+ band_1_null_chunk_rows[i_chunk_rows_pix] == 1 ||
-+ band_2_null_chunk_rows[i_chunk_rows_pix] == 1)
++ /* pixels already belongs to category from category raster conditions file or contains null value in one of the bands */
++ if(belongs_pix[i_rows_pix] ||
++ b_1_null_row[i_rows_pix] == 1 ||
++ b_2_null_row[i_rows_pix] == 1)
+ continue;
+
-+ array_idx = b_1_chunk_rows[i_chunk_rows_pix] - b_1_range.min + (b_2_chunk_rows[i_chunk_rows_pix] - b_2_range.min) * b_1_range_size;
-+ /*TODO test value */
++ array_idx = b_1_row[i_rows_pix] - b_1_range.min + (b_2_row[i_rows_pix] - b_2_range.min) * b_1_range_size;
+ if(array_idx < 0 || array_idx >= max_arr_idx) {
-+ G_warning ("pixel out of range");
++ G_warning ("Data inconsistent. Value computed for scatter plot is out of initialized range.");
+ continue;
+ }
++ /* pixels meets condtion defined in scatter plot */
+ if(i_scatt_conds[array_idx])
-+ belongs_pix[i_chunk_rows_pix] = 1;
++ belongs_pix[i_rows_pix] = 1;
+ }
+ }
+ }
+
++ /* update category raster with belonging pixels */
+ if(fd_cats_rasts[i_cat] >= 0) {
+ Rast_set_null_value(cat_rast_row, Rast_window_cols(), CELL_TYPE);
+
-+ for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
-+ if(belongs_pix[i_chunk_rows_pix])
-+ cat_rast_row[i_chunk_rows_pix] = belongs_pix[i_chunk_rows_pix];
++ for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)
++ if(belongs_pix[i_rows_pix])
++ cat_rast_row[i_rows_pix] = belongs_pix[i_rows_pix];
+
+ Rast_put_c_row (fd_cats_rasts[i_cat], cat_rast_row);
+ }
+
-+ update_cat_scatt_plts(chunk_rows, null_chunk_rows, chunk_row_size, belongs_pix, scatt_plts_scatts);
++ /* update scatter plots with belonging pixels */
++ update_cat_scatt_plts(bands_rows, belongs_pix, scatts_scatt_plts);
+ }
+
+ G_free(cat_rast_row);
@@ -4570,18 +4545,18 @@
+/*!
+ \brief Helper function for clean up.
+*/
-+static void free_compute_scatts_data(int * fd_bands, CELL ** chunk_rows, char ** null_chunk_rows, int * n_a_bands, int * bands_ids,
++static void free_compute_scatts_data(int * fd_bands, struct rast_row * bands_rows, int n_a_bands, int * bands_ids,
+ int * fd_cats_rasts, FILE ** f_cats_rasts_conds, int n_a_cats)
+{
+ int i, band_id;
+
-+ for(i = 0; i < (* n_a_bands); i++)
++ for(i = 0; i < n_a_bands; i++)
+ {
+ band_id = bands_ids[i];
+ if(band_id >= 0) {
+ Rast_close(fd_bands[i]);
-+ G_free(chunk_rows[band_id]);
-+ G_free(null_chunk_rows[band_id]);
++ G_free(bands_rows[band_id].row);
++ G_free(bands_rows[band_id].null_row);
+ }
+ }
+
@@ -4598,133 +4573,107 @@
+}
+
+/*!
-+ \brief Open pgm files.
-+*/
-+static int open_cats_rasts_files(const char ** cats_rasts, int n_a_cats, int * cats_ids, const char * mode, FILE ** fd_cats_rasts)
-+{
-+ int i_cat, id_cat;
++ \brief Compute scatter plots data.
+
-+ for(i_cat = 0; i_cat < n_a_cats; i_cat++)
-+ {
-+ id_cat = cats_ids[i_cat];
++ If category has not defined no category raster condition file and no scatter plot with consdtion,
++ default scatter plot is computed.
+
-+ if(cats_rasts[id_cat]) {
-+ fd_cats_rasts[i_cat] = fopen(cats_rasts[id_cat], mode);
-+ if(!fd_cats_rasts[i_cat]) return -1;
-+ }
-+ else
-+ fd_cats_rasts[i_cat] = NULL;
-+ }
-+
-+ return 0;
-+}
-+
-+/*!
-+ \brief Write header for pgm file.
-+*/
-+static int cats_rasts_write_header(int n_a_cats, struct Cell_head * region, FILE ** fd_cats_rasts)
-+{
-+ int i_cat, id_cat, head_nchars;
-+ char cat_rast_header[1024];//TODO magic number
-+
-+ head_nchars = get_cat_rast_header(region, cat_rast_header);
-+
-+ for(i_cat = 0; i_cat < n_a_cats; i_cat++)
-+ {
-+ if(!fd_cats_rasts[i_cat])
-+ continue;
-+
-+ fwrite(cat_rast_header, sizeof(char), head_nchars/sizeof(char), fd_cats_rasts[i_cat]);
-+ if (ferror(fd_cats_rasts[i_cat])) return -1;
-+ }
-+
-+ return head_nchars;
-+
-+}
-+
-+/*!
-+ \brief Computes scatter plots data.
-+
-+ \param region analysis region, beaware that cats_rasts_conds must be generated for this region
-+ \param scatt_conds pointer to scScatts struct of type SC_SCATT_CONDITIONS, where are selected areas (conditions) stored
-+ \param bands name of analyzed bands, order of bands id defined by their id
++ \param region analysis region, beaware that all input data must be prepared for this region (bands (their ranges), cats_rasts_conds rasters...)
++ \param region function calls Rast_set_window for this region
++ \param scatt_conds pointer to scScatts struct of type SC_SCATT_CONDITIONS, where are stored selected areas (conditions) in scatter plots
++ \param cats_rasts_conds paths to category raster conditions files representing selected areas (conditions) in rasters for every category
++ \param cats_rasts_conds index in array represents corresponding category id
++ \param cats_rasts_conds for manupulation with category raster conditions file see also I_id_scatt_to_bands() and I_insert_patch_to_cat_rast()
++ \param bands names of analyzed bands, order of bands is defined by their id
+ \param n_bands number of bands
-+ \param cats_rasts_conds paths to pgm files for every category representing selected areas (conditions) from mapwindow
-+ \param cats_rasts_conds location in the array is defined be category id
+ \param [out] scatts pointer to scScatts struct of type SC_SCATT_DATA, where are computed scatter plots stored
-+ \param [out] cats_rasts array of raster maps names where will be stored all selected pixels for category
++ \param [out] cats_rasts array of raster maps names where will be stored all selected pixels for every category
++
++ \return 0 on success
++ \return -1 on failure
+*/
-+int I_compute_scatts(struct Cell_head *region, struct scCats * scatt_conds, const char ** bands,
-+ int n_bands, const char ** cats_rasts_conds, struct scCats * scatts, const char ** cats_rasts)
++int I_compute_scatts(struct Cell_head *region, struct scCats * scatt_conds, const char ** cats_rasts_conds,
++ const char ** bands, int n_bands, struct scCats * scatts, const char ** cats_rasts)
+{
-+ if (n_bands != scatts->n_bands ||
-+ n_bands != scatt_conds->n_bands)
-+ return -4;
-+
+ const char *mapset;
+ char header[1024];
+
+ int fd_cats_rasts[scatt_conds->n_a_cats];
+ FILE * f_cats_rasts_conds[scatt_conds->n_a_cats];
+
-+ CELL * chunk_rows[n_bands];
-+ char * null_chunk_rows[n_bands];
++ struct rast_row bands_rows[n_bands];
+
+ RASTER_MAP_TYPE data_type;
+
-+ int nrows, i_band, id_band, n_a_bands, band_id,
-+ chunk_row_size, i, i_row, head_nchars, i_cat, id_cat;
++ int nrows, i_band, n_a_bands, band_id,
++ i, i_row, head_nchars, i_cat, id_cat;
++
+ int fd_bands[n_bands];
++ int bands_ids[n_bands];
++ int b_needed_bands[n_bands];
++
++ Rast_set_window(region);
++
+ for(i_band = 0; i_band < n_bands; i_band++)
+ fd_bands[i_band] = -1;
+
-+ int bands_ids[n_bands];
+ for(i_band = 0; i_band < n_bands; i_band++)
+ bands_ids[i_band] = -1;
+
-+ int b_needed_bands[n_bands];
++ if (n_bands != scatts->n_bands ||
++ n_bands != scatt_conds->n_bands)
++ return -1;
++
+ memset(b_needed_bands, 0, (size_t)n_bands * sizeof(int));
+
+ get_needed_bands(scatt_conds, &b_needed_bands[0]);
+ get_needed_bands(scatts, &b_needed_bands[0]);
+
-+ Rast_set_window(region);
++ n_a_bands = 0;
+
-+ n_a_bands = 0;/*TODO realy needed?*/
-+ for(id_band = 0; id_band < n_bands; id_band++)
++ /* open band rasters, which are needed for computation */
++ for(band_id = 0; band_id < n_bands; band_id++)
+ {
-+ if(b_needed_bands[id_band])
++ if(b_needed_bands[band_id])
+ {
-+ G_debug(3, "Opening raster no. %d with name: %s", id_band, bands[id_band]);
++ G_debug(3, "Opening raster no. %d with name: %s", band_id, bands[band_id]);
+
-+ /* TODO solve returns*/
-+ if ((mapset = G_find_raster2(bands[id_band],"")) == NULL) {
-+ free_compute_scatts_data(&fd_bands[0], &chunk_rows[0], &null_chunk_rows[0], &n_a_bands,
-+ &bands_ids[0], NULL, NULL, scatt_conds->n_a_cats);
-+ return -4;
++ if ((mapset = G_find_raster2(bands[band_id],"")) == NULL) {
++ free_compute_scatts_data(fd_bands, bands_rows, n_a_bands,
++ bands_ids, NULL, NULL, scatt_conds->n_a_cats);
++ G_warning(_("Unbale to read find raster <%s>"), bands[band_id]);
++ return -1;
+ }
+
-+ if ((fd_bands[n_a_bands] = Rast_open_old(bands[id_band], mapset)) < 0) {
-+ free_compute_scatts_data(&fd_bands[0], &chunk_rows[0], &null_chunk_rows[0], &n_a_bands,
-+ &bands_ids[0], NULL, NULL, scatt_conds->n_a_cats);
-+ return -5;
++ if ((fd_bands[n_a_bands] = Rast_open_old(bands[band_id], mapset)) < 0) {
++ free_compute_scatts_data(fd_bands, bands_rows, n_a_bands,
++ bands_ids, NULL, NULL, scatt_conds->n_a_cats);
++ G_warning(_("Unbale to open raster <%s>"), bands[band_id]);
++ return -1;
+ }
+
-+ //TODO check data type, minimum and maximum value
+ data_type = Rast_get_map_type(fd_bands[n_a_bands]);
-+ //if(data_type != CELL)
-+ // return -1;
++ if(data_type != CELL_TYPE) {
++ G_warning(_("Raster <%s> type is not <%s>"), bands[band_id], "CELL");
++ return -1;
++ }
+
-+ //What happens if it is not CELL tyoe
-+ chunk_rows[id_band] = Rast_allocate_c_buf();
-+ null_chunk_rows[id_band] = Rast_allocate_null_buf();
++ bands_rows[band_id].row = Rast_allocate_c_buf();
++ bands_rows[band_id].null_row = Rast_allocate_null_buf();
+
-+ bands_ids[n_a_bands] = id_band;
++ if(Rast_read_range(bands[band_id], mapset, &bands_rows[band_id].rast_range) != 1){
++ free_compute_scatts_data(fd_bands, bands_rows, n_a_bands,
++ bands_ids, NULL, NULL, scatt_conds->n_a_cats);
++ G_warning(_("Unable to read range of raster <%s>"), bands[band_id]);
++ return -1;
++ }
+
++ bands_ids[n_a_bands] = band_id;
+ ++n_a_bands;
+ }
+ }
+
++ /* open category rasters condition files and category rasters */
+ for(i_cat = 0; i_cat < scatts->n_a_cats; i_cat++)
+ {
+ id_cat = scatts->cats_ids[i_cat];
@@ -4733,42 +4682,49 @@
+ }
+ else
+ fd_cats_rasts[i_cat] = -1;
-+ }
+
-+ head_nchars = get_cat_rast_header(region, header);
-+
-+ if (open_cats_rasts_files(cats_rasts_conds, scatt_conds->n_a_cats, scatt_conds->cats_ids, "rb", f_cats_rasts_conds) != 0) {
-+ free_compute_scatts_data(&fd_bands[0], &chunk_rows[0], &null_chunk_rows[0], &n_a_bands,
-+ &bands_ids[0], &fd_cats_rasts[0], &f_cats_rasts_conds[0], scatt_conds->n_a_cats);
-+ return -2;
++ if(cats_rasts_conds[id_cat]) {
++ f_cats_rasts_conds[i_cat] = fopen(cats_rasts_conds[id_cat], "r");
++ if(!f_cats_rasts_conds[i_cat]) {
++ free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, bands_ids,
++ f_cats_rasts_conds, f_cats_rasts_conds, scatt_conds->n_a_cats);
++ G_warning(_("Unable to open category raster condtition file <%s>"), bands[band_id]);
++ return -1;
++ }
++ }
++ else
++ f_cats_rasts_conds[i_cat] = NULL;
+ }
+
++ head_nchars = get_cat_rast_header(region, header);
+ for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
+ if(f_cats_rasts_conds[i_cat])
-+ fseek(f_cats_rasts_conds[i_cat] , head_nchars, SEEK_SET);
++ if( fseek(f_cats_rasts_conds[i_cat] , head_nchars, SEEK_SET) != 0) {
++ G_warning(_("Corrupted category raster conditions file (fseek failed)"));
++ return -1;
++ }
+
+ nrows = Rast_window_rows();
-+ chunk_row_size = Rast_window_cols();
+
++ /* analyze bands by rows */
+ for (i_row = 0; i_row < nrows; i_row++)
+ {
+ for(i_band = 0; i_band < n_a_bands; i_band++)
+ {
+ band_id = bands_ids[i_band];
-+ G_debug(3, "Reading data for band %d", band_id);
-+ Rast_get_c_row(fd_bands[i_band], chunk_rows[band_id], i_row);
-+ Rast_get_null_value_row (fd_bands[i_band], null_chunk_rows[band_id], i_row);
++ Rast_get_c_row(fd_bands[i_band], bands_rows[band_id].row, i_row);
++ Rast_get_null_value_row (fd_bands[i_band], bands_rows[band_id].null_row, i_row);
+ }
-+ if(compute_scatts_from_chunk_row(scatts, scatt_conds, chunk_rows, null_chunk_rows, chunk_row_size, &f_cats_rasts_conds[0], &fd_cats_rasts[0], region) == -1)
++ if(compute_scatts_from_chunk_row(region, scatt_conds, f_cats_rasts_conds, bands_rows, scatts, fd_cats_rasts) == -1)
+ {
-+ free_compute_scatts_data(&fd_bands[0], &chunk_rows[0], &null_chunk_rows[0], &n_a_bands,
-+ &bands_ids[0], &fd_cats_rasts[0], &f_cats_rasts_conds[0], scatt_conds->n_a_cats);
-+ return -3;
++ free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, bands_ids, fd_cats_rasts,
++ f_cats_rasts_conds, scatt_conds->n_a_cats);
++ return -1;
+ }
+
+ }
-+ free_compute_scatts_data(&fd_bands[0], &chunk_rows[0], &null_chunk_rows[0], &n_a_bands,
-+ &bands_ids[0], &fd_cats_rasts[0], &f_cats_rasts_conds[0], scatt_conds->n_a_cats);
++ free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, bands_ids,
++ fd_cats_rasts, f_cats_rasts_conds, scatt_conds->n_a_cats);
+ return 0;
+}
\ No newline at end of file
More information about the grass-commit
mailing list