[GRASS-SVN] r57440 - sandbox/turek/scatter_plot
svn_grass at osgeo.org
svn_grass at osgeo.org
Sat Aug 10 00:20:08 PDT 2013
Author: turek
Date: 2013-08-10 00:20:08 -0700 (Sat, 10 Aug 2013)
New Revision: 57440
Modified:
sandbox/turek/scatter_plot/testing_patch.diff
Log:
scatter plot: new layout and other changes and fixes
Modified: sandbox/turek/scatter_plot/testing_patch.diff
===================================================================
--- sandbox/turek/scatter_plot/testing_patch.diff 2013-08-09 08:26:52 UTC (rev 57439)
+++ sandbox/turek/scatter_plot/testing_patch.diff 2013-08-10 07:20:08 UTC (rev 57440)
@@ -1,114 +1,35 @@
-Index: vector/v.edit/main.c
+Index: include/defs/vedit.h
===================================================================
---- vector/v.edit/main.c (revision 57336)
-+++ vector/v.edit/main.c (working copy)
-@@ -299,7 +299,7 @@
- move_z = atof(params.move->answers[2]);
- G_verbose_message(_("Threshold value for snapping is %.2f"),
- thresh[THRESH_SNAP]);
-- ret = Vedit_move_lines(&Map, BgMap, nbgmaps, List, move_x, move_y, move_z, snap, thresh[THRESH_SNAP]);
-+ ret = Vedit_move_lines(&Map, BgMap, nbgmaps, List, move_x, move_y, move_z, snap, thresh[THRESH_SNAP], NULL);
- G_message(_("%d features moved"), ret);
- break;
- case MODE_VERTEX_MOVE:
-@@ -308,15 +308,15 @@
- move_z = atof(params.move->answers[2]);
- G_verbose_message(_("Threshold value for snapping is %.2f"),
- thresh[THRESH_SNAP]);
-- ret = Vedit_move_vertex(&Map, BgMap, nbgmaps, List, coord, thresh[THRESH_COORDS], thresh[THRESH_SNAP], move_x, move_y, move_z, move_first, snap);
-+ ret = Vedit_move_vertex(&Map, BgMap, nbgmaps, List, coord, thresh[THRESH_COORDS], thresh[THRESH_SNAP], move_x, move_y, move_z, move_first, snap, NULL);
- G_message(_("%d vertices moved"), ret);
- break;
- case MODE_VERTEX_ADD:
-- ret = Vedit_add_vertex(&Map, List, coord, thresh[THRESH_COORDS]);
-+ ret = Vedit_add_vertex(&Map, List, coord, thresh[THRESH_COORDS], NULL);
- G_message(_("%d vertices added"), ret);
- break;
- case MODE_VERTEX_DELETE:
-- ret = Vedit_remove_vertex(&Map, List, coord, thresh[THRESH_COORDS]);
-+ ret = Vedit_remove_vertex(&Map, List, coord, thresh[THRESH_COORDS], NULL);
- G_message(_("%d vertices removed"), ret);
- break;
- case MODE_BREAK:
-Index: include/imagery.h
-===================================================================
---- include/imagery.h (revision 57336)
-+++ include/imagery.h (working copy)
-@@ -135,6 +135,48 @@
-
- } IClass_statistics;
+--- include/defs/vedit.h (revision 57437)
++++ include/defs/vedit.h (working copy)
+@@ -33,6 +33,8 @@
+ int Vedit_merge_lines(struct Map_info *, struct ilist *);
-+/* Scatter Plot backend */
-+struct scCats
-+{
-+ int type; //TODO do not identify it with number
-+
-+ int n_cats;
-+
-+ int n_bands;
-+ int n_scatts;
-+
-+ int n_a_cats;
-+ int * cats_ids;
-+ int * cats_idxs;
-+
-+ struct scScatts ** cats_arr;
-+};
-+
-+struct scScatts
-+{
-+ int n_a_scatts;
-+
-+ int * scatts_bands;
-+ int * scatt_idxs;
-+
-+ struct scdScattData ** scatts_arr;
-+};
-+
-+#define SC_SCATT_DATA 0
-+#define SC_SCATT_CONDITIONS 1
-+
-+struct scdScattData
-+{
-+ int n_vals; //TODO delete???
-+
-+ struct Range band_1_range;
-+ struct Range band_2_range;
-+
-+
-+ unsigned char * b_conds_arr;
-+ unsigned int * scatt_vals_arr;
-+};
-+
- #define SIGNATURE_TYPE_MIXED 1
+ /* move.c */
++int Vedit_move_areas(struct Map_info *, struct Map_info **, int,
++ struct ilist *, double, double, double, int, double);
+ int Vedit_move_lines(struct Map_info *, struct Map_info **, int,
+ struct ilist *, double, double, double, int, double);
- #define GROUPFILE "CURGROUP"
Index: include/defs/imagery.h
===================================================================
---- include/defs/imagery.h (revision 57336)
+--- include/defs/imagery.h (revision 57437)
+++ include/defs/imagery.h (working copy)
-@@ -110,6 +110,29 @@
+@@ -110,6 +110,22 @@
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 *);
-+void I_sc_get_active_categories(int *, int *, struct scCats *);
+int I_sc_add_cat(struct scCats *, int);
-+int I_sc_delete_cat(struct scCats *, int);
+int I_sc_insert_scatt_data(struct scCats *, struct scdScattData *, int, int);
-+int I_sc_remove_scatt_data(struct scCats *, struct scdScattData *, int, int);
-+int I_sc_set_value(struct scCats *, int, int, 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_get_range_min_max(struct scdScattData *, CELL *, CELL *, CELL *, CELL *);
-+void * I_scd_get_data_ptr(struct scdScattData *);
-+int I_scd_set_value(struct scdScattData *, unsigned int, unsigned int);
+
+int I_compute_scatts(struct Cell_head *, struct scCats *, const char **,
-+ int, struct scCats *, const char **, const char **);
++ int, const char **, 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 *);
@@ -117,1264 +38,410 @@
/* sig.c */
int I_init_signatures(struct Signature *, int);
int I_new_signature(struct Signature *);
-Index: include/defs/vedit.h
+Index: include/imagery.h
===================================================================
---- include/defs/vedit.h (revision 57336)
-+++ include/defs/vedit.h (working copy)
-@@ -34,7 +34,7 @@
+--- include/imagery.h (revision 57437)
++++ include/imagery.h (working copy)
+@@ -135,6 +135,59 @@
+
+ } IClass_statistics;
- /* move.c */
- int Vedit_move_lines(struct Map_info *, struct Map_info **, int,
-- struct ilist *, double, double, double, int, double);
-+ struct ilist *, double, double, double, int, double, struct ilist *);
-
- /* render.c */
- struct robject_list *Vedit_render_map(struct Map_info *, struct bound_box *, int,
-@@ -56,11 +56,11 @@
- int Vedit_move_vertex(struct Map_info *, struct Map_info **, int,
- struct ilist *,
- struct line_pnts *, double, double,
-- double, double, double, int, int);
-+ double, double, double, int, int, struct ilist *);
- int Vedit_add_vertex(struct Map_info *Map, struct ilist *,
-- struct line_pnts *, double);
-+ struct line_pnts *, double, struct ilist *);
- int Vedit_remove_vertex(struct Map_info *, struct ilist *,
-- struct line_pnts *, double);
-+ struct line_pnts *, double, struct ilist *);
-
- /* zbulk.c */
- int Vedit_bulk_labeling(struct Map_info *, struct ilist *,
-Index: gui/wxpython/scatt_plot/controllers.py
-===================================================================
---- gui/wxpython/scatt_plot/controllers.py (revision 0)
-+++ gui/wxpython/scatt_plot/controllers.py (working copy)
-@@ -0,0 +1,518 @@
-+"""!
-+ at package scatt_plot.controllers
++/* Scatter Plot backend */
+
-+ at brief Controller layer for scatter plot tool.
++#define SC_SCATT_DATA 0
++#define SC_SCATT_CONDITIONS 1
+
-+Classes:
+
-+(C) 2013 by the GRASS Development Team
++/*! Holds list of all catagories.
++ It can contain selected areas for scatter plots (SC_SCATT_CONDITIONS type) or computed scatter plots (SC_SCATT_DATA type).
++*/
++struct scCats
++{
++ int type; /*!< SC_SCATT_DATA -> computed scatter plots, SC_SCATT_CONDITIONS -> set conditions for scatter plots*/
+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
++ 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 */
+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+import os
-+import sys
++ int n_a_cats; /*!< number of used categories */
++ int * cats_ids; /*!< category id */
++ int * cats_idxs; /*!< internal category idx (idx in cats_arr)*/
+
-+#TODO
-+import wx
++ struct scScatts ** cats_arr; /*!< array of pointers to struct scScatts */
++};
+
-+from core.gcmd import GException, GError, RunCommand
+
-+from scatt_plot.sc_pl_core import Core, idBandsToidScatt
++/*! Holds list of all scatter plots, which belongs to category.
++*/
++struct scScatts
++{
++ int n_a_scatts; /*!< number of used 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)*/
+
-+from scatt_plot.gthreading import gThread
-+from core.gconsole import EVT_CMD_DONE
++ struct scdScattData ** scatts_arr; /*!< array of pointers to scdScattData */
++};
+
-+from grass.pydispatch.signal import Signal
++/*! Holds scatter plot data.
++*/
++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) */
+
-+class ScattsManager(wx.EvtHandler):
-+ def __init__(self, guiparent, giface, iclass_mapwin):
-+ #TODO remove iclass parameter
+
-+ wx.EvtHandler.__init__(self)
-+ self.giface = giface
-+ self.mapDisp = giface.GetMapDisplay()
-+ self.mapWin = giface.GetMapWindow()
++ 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) */
++};
+
-+ if iclass_mapwin:
-+ self.mapWin = iclass_mapwin
-+
-+ self.guiparent = guiparent
-+
-+ self.core = Core()
-+ self.scatts_dt = self.core.GetScattsData()
-+
-+ self.cats_mgr = CategoriesManager(self, self.core)
-+
-+ self.thread = gThread(self);
-+
-+ self.scatt_plts = {}
-+ self.added_cats_rasts = {}
-+
-+ self.cats_to_update = []
-+
-+ self.edit_cat_type = None
-+
-+ self.data_set = False
-+
-+ if iclass_mapwin:
-+ self.mapWin_conn = MapWinConnection(self, self.mapWin, self.core.CatRastUpdater())
-+ self.iclass_conn = IClassConnection(self, iclass_mapwin.parent, self.cats_mgr)
+ #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:
-+ self.mapWin_conn = None
-+ self.iclass_conn = None
++ cat = None
+
-+ self.tasks_pids = {
-+ 'add_scatt' : [],
-+ 'set_data' : -1,
-+ 'set_edit_cat_data' : -1,
-+ 'mapwin_conn' : [],
-+ 'render_plots' : -1
-+ }
+ if toolbar.choice.IsEmpty():
+ toolbar.EnableControls(False)
+ else:
+ toolbar.EnableControls(True)
+
-+ self.Bind(EVT_CMD_DONE, self.OnThreadDone)
++ 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
+
-+ def SetData(self, bands):
-+ self.data_set = False
-+ self.tasks_pids['set_data'] = self.thread.GetId()
-+ self.thread.Run(callable = self.core.SetData, bands = bands)
+ class IClassMapFrame(DoubleMapFrame):
+ """! wxIClass main frame
+
+@@ -115,6 +117,10 @@
+ lambda:
+ self.statusbarManager.statusbarItems['coordinates'].SetAdditionalInfo(None))
+ self.SetSize(size)
+
-+ #for i in range(1):
-+ # self.AddScattPlot(i)
++ self.groupSet = Signal("IClassMapFrame.groupSet")
++ self.categoryChanged = Signal('IClassMapFrame.categoryChanged')
+
-+ def SetDataDone(self, event):
-+ self.data_set = True
-+ self.cats_mgr.InitCoreCats()
-+
-+ def OnOutput(self, event):
-+ """!Print thread output according to debug level.
+ #
+ # 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
+ """
-+ print event.text
-+
-+ def GetBands(self):
-+ return self.core.GetBands()
-+
-+ def AddScattPlot(self, scatt_id):
-+
-+ self.tasks_pids['add_scatt'].append(self.thread.GetId())
-+ self.thread.Run(callable = self.core.AddScattPlot, scatt_id = scatt_id)
-+
-+ def RenderScattPlts(self):
-+
-+ cats_attrs = self.cats_mgr.GetCategoriesAttrs()
-+ for scatt_id, scatt in self.scatt_plts.iteritems():
-+ scatt_dt = self.scatts_dt.GetScatt(scatt_id)
-+ scatt.Plot(scatt_dt, cats_attrs)
-+
-+
-+ def AddScattPlotDone(self, event):
-+
-+ scatt_id = event.kwds['scatt_id']
-+
-+ #TODO guiparent - not very good
-+ self.scatt_plts[scatt_id] = self.guiparent.NewScatterPlot(scatt_id = scatt_id)
-+
-+ if self.edit_cat_type:
-+ self.scatt_plts[scatt_id].StartCategoryEdit()
-+
-+ scatt_dt = self.scatts_dt.GetScatt(scatt_id)
-+
-+ cats_attrs = self.cats_mgr.GetCategoriesAttrs()
-+
-+ self.scatt_plts[scatt_id].Plot(scatt_dt, cats_attrs)
-+ #for scatt in scatt_dt.itervalues():
-+ # del scatt
-+ self.scatt_plts[scatt_id].GetParent().Show()
-+ print "ok %d" % scatt_id
-+
-+ def CleanUp(self):
-+ self.core.CleanUp()
-+
-+ for scatt_id, scatt in self.scatt_plts.items():
-+ scatt.CleanUp()
-+ del self.scatt_plts[scatt_id]
-+
-+ def OnThreadDone(self, event):
-+
-+ if event.exception:
-+ GError(str(event.exception))
++ if self.dialogs['scatt_plot']:
++ self.dialogs['scatt_plot'].Raise()
+ return
+
-+ if event.pid in self.tasks_pids['mapwin_conn']:
-+ self.tasks_pids['mapwin_conn'].remove(event.pid)
-+ updated_cats = event.ret
++ try:
++ from scatt_plot.dialogs import ScattPlotMainDialog
++ self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface, iclass_mapwin = self.GetFirstWindow())
+
-+ for cat in updated_cats:
-+ if cat not in self.cats_to_update:
-+ self.cats_to_update.append(cat)
++ scatt_mgr = self.dialogs['scatt_plot'].GetScattMgr()
++ scatt_mgr.DigitDataChanged(self.toolbars['vdigit'].mapLayer.GetName(), self.GetFirstWindow().digit)
+
-+ if not self.tasks_pids['mapwin_conn']:
-+ self.tasks_pids['render_plots'] = self.thread.GetId()
-+ self.thread.Run(callable = self.core.ComputeCatScatts,
-+ cats_ids = self.cats_to_update[:])
-+ del self.cats_to_update[:]
-+
-+ return
++ self.dialogs['scatt_plot'].CenterOnScreen()
++ self.dialogs['scatt_plot'].Show()
+
-+ if self.tasks_pids['render_plots'] == event.pid:
-+ #TODO how to put it to the thread - kils gui
-+ self.RenderScattPlts()
-+ return
-+
-+ if event.pid in self.tasks_pids['add_scatt']:
-+ self.AddScattPlotDone(event)
-+ return
++ 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
+
-+ if self.tasks_pids['set_data'] == event.pid:
-+ self.SetDataDone(event)
-+ return
-+
-+ if self.tasks_pids['set_edit_cat_data'] == event.pid:
-+ self.SetEditCatDataDone(event)
-+ 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)
+
-+ def EditCat(self, edit_type):
-+
-+ self.edit_cat_type = edit_type
-+
-+ if self.edit_cat_type:
-+ for scatt in self.scatt_plts.itervalues():
-+ scatt.StopCategoryEdit()
-+ scatt.StartCategoryEdit()
-+
-+ else:
-+ for scatt in self.scatt_plts.itervalues():
-+ scatt.StopCategoryEdit()
-+
-+ def SetEditCatData(self, scatt_id, bbox):
-+
-+ value = 1
-+ if self.edit_cat_type == 'remove':
-+ value = 0
-+
-+ self.tasks_pids['set_edit_cat_data'] = self.thread.GetId()
-+
-+ sel_cat_id = self.cats_mgr.GetSelectedCat()
-+
-+ self.thread.Run(callable = self.core.SetEditCatData,
-+ scatt_id = scatt_id,
-+ cat_id = sel_cat_id,
-+ bbox = bbox,
-+ value = value)
-+
-+ def SetEditCatDataDone(self, event):
-+
-+ self.RenderScattPlts()
-+
-+ cat_id = event.kwds["cat_id"]
-+
-+ cat_rast = self.core.GetCatRastOut(cat_id)
-+
-+
-+ if cat_rast not in self.added_cats_rasts.values():
-+
-+ cats_attrs = self.cats_mgr.GetCategoryAttrs(cat_id)
-+
-+ #TODO use standard raster lib
-+ name = "cat_%d" % cat_id
-+ ret, err_msg = RunCommand('r.external',
-+ output = name,
-+ getErrorMsg = True,
-+ input = cat_rast,
-+ flags = "o",
-+ overwrite = True)
-+
-+ if ret != 0:
-+ GError(_("r.external failed\n%s" % err_msg))
-+
-+ region = self.core.GetRegion()
-+ ret, err_msg = RunCommand('r.region',
-+ map = name,
-+ getErrorMsg = True,
-+ n = "%f" % region['n'],
-+ s = "%f" % region['s'],
-+ e = "%f" % region['e'],
-+ w = "%f" % region['w'],
-+ )
-+
-+ region = self.core.GetRegion()
-+ ret, err_msg = RunCommand('r.colors',
-+ map = name,
-+ rules = "-",
-+ stdin = "1 %s" % cats_attrs["color"],
-+ getErrorMsg = True)
-+
-+ if ret != 0:
-+ GError(_("r.region failed\n%s" % err_msg))
-+
-+ self.mapWin.Map.AddLayer(ltype = "raster", name = "cat_%d" % cat_id, render = True,
-+ command = ["d.rast", "map=%s" % name, "values=1"])
-+
-+ #elif self.giface.GetLayerTree():
-+ # self.giface.GetLayerTree().AddLayer("raster", lname = "cat_%d" % cat_id, lchecked = True,
-+ # lcmd = ["d.rast", "map=%s" % name, "values=1"])
-+
-+ if ret != 0:
-+ GError(_("r.region failed\n%s" % err_msg))
-+
-+ self.added_cats_rasts[cat_id] = cat_rast
-+
-+ self.giface.updateMap.emit()
-+
-+ def DigitDataChanged(self, vectMap, digit):
-+
-+ if self.mapWin_conn:
-+ self.mapWin_conn.DigitDataChanged(vectMap, digit)
-+ return 1
-+ else:
-+ return 0
-+
-+ def GetCategoriesManager(self):
-+ return self.cats_mgr
-+
-+class CategoriesManager:
-+
-+ def __init__(self, scatt_mgr, core):
-+
-+ self.core = core
-+ self.scatt_mgr = scatt_mgr
-+
-+ self.cats = {}
-+ self.cats_ids = []
-+
-+ self.sel_cat_id = -1
-+
-+ self.initialized = Signal('CategoriesManager.initialized')
-+ self.setCategoryAttrs = Signal('CategoriesManager.setCategoryAttrs')
-+ self.deletedCategory = Signal('CategoriesManager.deletedCategory')
-+ self.addedCategory = Signal('CategoriesManager.addedCategory')
-+
-+ def Clear(self):
-+
-+ self.cats.clear()
-+ del self.cats_ids[:]
-+
-+ self.sel_cat_id = -1
-+
-+ def InitCoreCats(self):
-+ if self.scatt_mgr.data_set:
-+ for cat_id in self.cats_ids:
-+ self.core.AddCategory(cat_id)
-+
-+ def AddCategory(self, cat_id = None, name = None, color = None):
-+
-+ if cat_id is None:
-+ if self.cats_ids:
-+ cat_id = max(self.cats_ids) + 1
-+ else:
-+ cat_id = 1
-+
-+ if self.scatt_mgr.data_set:
-+ ret = self.core.AddCategory(cat_id)
-+ if ret < 0: #TODO
-+ return -1;
-+
-+ self.cats[cat_id] = {
-+ 'name' : _('Category %s' % cat_id ),
-+ 'color' : "0:0:0"
-+ }
-+ self.cats_ids.append(cat_id)
-+
-+ if name is not None:
-+ self.cats[cat_id]["name"] = name
-+
-+ if color is not None:
-+ self.cats[cat_id]["color"] = color
-+
-+ self.addedCategory.emit(cat_id = cat_id,
-+ name = self.cats[cat_id]["name"],
-+ color = self.cats[cat_id]["color"] )
-+ return cat_id
-+
-+ def SetCategoryAttrs(self, cat_id, attrs_dict):
-+ for k, v in attrs_dict.iteritems():
-+ self.cats[cat_id][k] = v
-+
-+ self.setCategoryAttrs.emit(cat_id = cat_id, attrs_dict = attrs_dict)
-+
-+ def DeleteCategory(self, cat_id):
-+
-+ if self.scatt_mgr.data_set:
-+ self.core.DeleteCategory(cat_id)
-+ del self.cats[cat_id]
-+ self.cats_ids.remove(cat_id)
-+
-+ self.deletedCategory.emit(cat_id = cat_id)
-+
-+ #TODO emit event?
-+ def SetSelectedCat(self, cat_id):
-+ self.sel_cat_id = cat_id
-+
-+ def GetSelectedCat(self):
-+ return self.sel_cat_id
-+
-+ def GetCategoryAttrs(self, cat_id):
-+ #TODO is mutable
-+ return self.cats[cat_id]
-+
-+ def GetCategoriesAttrs(self):
-+ #TODO is mutable
-+ return self.cats
-+
-+ def GetCategories(self):
-+ return self.cats_ids[:]
-+
-+class MapWinConnection:
-+ def __init__(self, scatt_mgr, mapWin, scatt_rast_updater):
-+ self.mapWin = mapWin
-+ self.vectMap = None
-+ self.scatt_rast_updater = scatt_rast_updater
-+ self.scatt_mgr = scatt_mgr
-+ self.cats_mgr = scatt_mgr.cats_mgr
-+
-+ self.thread = self.scatt_mgr.thread
-+
-+ #TODO
-+ self.mapWin.parent.toolbars["vdigit"].editingStarted.connect(self.DigitDataChanged)
-+
-+ #def ChangeMap(self, vectMap, layers_cats):
-+ # self.vectMap = vectMap
-+ # self.layers_cats = layers_cats
-+
-+ #ret, region, msg = RunCommand("v.to.rast",
-+ # flags = "gp",
-+ # getErrorMsg = True,
-+ # read = True)
-+
-+ def _connectSignals(self):
-+ self.digit.featureAdded.connect(self.AddFeature)
-+ self.digit.areasDeleted.connect(self.DeleteAreas)
-+ self.digit.featuresDeleted.connect(self.DeleteAreas)
-+ self.digit.vertexMoved.connect(self.ChangeVertex)
-+ self.digit.vertexRemoved.connect(self.ChangeVertex)
-+ self.digit.lineEdited.connect(self.ChangeVertex)
-+ self.digit.featuresMoved.connect(self.MoveFeatures)
-+
-+ def AddFeature(self, new_geom, cat):
-+ if not self.scatt_mgr.data_set:
-+ return
-+
-+ self.scatt_mgr.tasks_pids['mapwin_conn'].append(self.thread.GetId())
-+ self.thread.Run(callable = self.scatt_rast_updater.AddedFeature,
-+ new_geom = new_geom,
-+ cat = cat)
-+
-+ def DeleteAreas(self, old_geoms, old_areas_cats):
-+ if not self.scatt_mgr.data_set:
-+ return
-+
-+ self.scatt_mgr.tasks_pids['mapwin_conn'].append(self.thread.GetId())
-+ self.thread.Run(callable = self.scatt_rast_updater.DeletedAreas,
-+ old_geoms = old_geoms,
-+ old_areas_cats = old_areas_cats)
-+
-+ def ChangeVertex(self, new_geom, new_areas_cats, old_geom, old_areas_cats):
-+ if not self.scatt_mgr.data_set:
-+ return
-+
-+ self.scatt_mgr.tasks_pids['mapwin_conn'].append(self.thread.GetId())
-+ self.thread.Run(callable = self.scatt_rast_updater.ChangedVertex,
-+ new_geom = new_geom,
-+ old_geom = old_geom,
-+ old_areas_cats = old_areas_cats,
-+ new_areas_cats = new_areas_cats)
-+
-+ def MoveFeatures(self, old_geoms, old_areas_cats, new_areas_cats, move):
-+ if not self.scatt_mgr.data_set:
-+ return
-+
-+ self.scatt_mgr.tasks_pids['mapwin_conn'].append(self.thread.GetId())
-+ self.thread.Run(callable = self.scatt_rast_updater.MovedFeatures,
-+ move = move,
-+ old_geoms = old_geoms,
-+ old_areas_cats = old_areas_cats,
-+ new_areas_cats = new_areas_cats)
-+
-+ def DigitDataChanged(self, vectMap, digit):
-+
-+ self.digit = digit
-+ self.vectMap = vectMap
-+
-+ self.scatt_rast_updater.SetVectMap(vectMap)
-+
-+ self._connectSignals()
-+
-+class IClassConnection:
-+ def __init__(self, scatt_mgr, iclass_frame, cats_mgr):
-+ self.iclass_frame = iclass_frame
-+ self.stats_data = self.iclass_frame.stats_data
-+ self.cats_mgr = cats_mgr
-+ self.scatt_mgr = scatt_mgr
-+
-+ self.stats_data.statisticsAdded.connect(self.AddCategory)
-+ self.stats_data.statisticsDeleted.connect(self.DeleteCategory)
-+ self.stats_data.allStatisticsDeleted.connect(self.DeletAllCategories)
-+ self.stats_data.statisticsSet.connect(self.SetCategory)
-+
-+ self.cats_mgr.setCategoryAttrs.connect(self.SetStatistics)
-+ self.cats_mgr.deletedCategory.connect(self.DeleteStatistics)
-+ self.cats_mgr.addedCategory.connect(self.AddStatistics)
-+
-+ self.SyncCats()
-+
-+ def SyncCats(self):
-+ self.cats_mgr.addedCategory.disconnect(self.AddStatistics)
-+ cats = self.stats_data.GetCategories()
-+ for c in cats:
-+ stats = self.stats_data.GetStatistics(c)
-+ self.cats_mgr.AddCategory(c, stats.name, stats.color)
-+ self.cats_mgr.addedCategory.connect(self.AddStatistics)
-+
-+ def AddCategory(self, cat, name, color):
-+ self.cats_mgr.addedCategory.disconnect(self.AddStatistics)
-+ self.cats_mgr.AddCategory(cat_id = cat, name = name, color = color)
-+ self.cats_mgr.addedCategory.connect(self.AddStatistics)
-+
-+ def DeleteCategory(self, cat):
-+ self.cats_mgr.deletedCategory.disconnect(self.DeleteStatistics)
-+ self.cats_mgr.DeleteCategory(cat)
-+ self.cats_mgr.deletedCategory.connect(self.DeleteStatistics)
-+
-+
-+ def DeletAllCategories(self):
-+
-+ self.cats_mgr.deletedCategory.disconnect(self.DeleteStatistics)
-+ cats = self.stats_data.GetCategories()
-+ for c in cats:
-+ self.cats_mgr.DeleteCategory(c)
-+ self.cats_mgr.deletedCategory.connect(self.DeleteStatistics)
-+
-+ def SetCategory(self, cat, stats):
-+
-+ self.cats_mgr.setCategoryAttrs.disconnect(self.SetStatistics)
-+ cats_attr = {}
-+ for attr in ['name', 'color']:
-+ if stats.has_key(attr):
-+ cats_attr[attr] = stats[attr]
-+
-+ if cats_attr:
-+ self.cats_mgr.SetCategoryAttrs(cat, cats_attr)
-+ self.cats_mgr.setCategoryAttrs.connect(self.SetStatistics)
-+
-+
-+ def SetStatistics(self, cat_id, attrs_dict):
-+ self.stats_data.statisticsSet.disconnect(self.SetCategory)
-+ self.stats_data.GetStatistics(cat_id).SetStatistics(attrs_dict)
-+ self.stats_data.statisticsSet.connect(self.SetCategory)
-+
-+ def AddStatistics(self, cat_id, name, color):
-+ self.stats_data.statisticsAdded.disconnect(self.AddCategory)
-+ self.stats_data.AddStatistics(cat_id, name, color)
-+ self.stats_data.statisticsAdded.connect(self.AddCategory)
-+
-+ def DeleteStatistics(self, cat_id):
-+ self.stats_data.statisticsDeleted.disconnect(self.DeleteCategory)
-+ self.stats_data.DeleteStatistics(cat_id)
-+ self.stats_data.statisticsDeleted.connect(self.DeleteCategory)
-Index: gui/wxpython/scatt_plot/sc_pl_core.py
++ 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/scatt_plot/sc_pl_core.py (revision 0)
-+++ gui/wxpython/scatt_plot/sc_pl_core.py (working copy)
-@@ -0,0 +1,697 @@
-+"""!
-+ at package scatt_plot.scatt_plot
+--- 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
+
-+ at brief Non GUI functions.
+ self.mainSizer = wx.BoxSizer(wx.VERTICAL)
+-
+
-+Classes:
+ self._createControlPanel()
+-
++ self._createPlotPanel()
++ self._createScatterPlotPanel()
+
-+(C) 2013 by the GRASS Development Team
+ self.SetSizer(self.mainSizer)
+ self.mainSizer.Fit(self)
+ self.Layout()
+
++ def _createPlotPanel(self):
+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
++ 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)
+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+import os
-+import sys
-+
-+#TODO
-+import time
-+
-+import numpy as np
-+
-+from math import sqrt, ceil, floor
-+from copy import deepcopy
-+
-+from grass.script import core as grass
-+from core.gcmd import GException, GError, RunCommand
-+
-+import grass.script as grass
-+
-+from core_c import CreateCatRast, ComputeScatts, UpdateCatRast, \
-+ SC_SCATT_DATA, SC_SCATT_CONDITIONS
-+
-+class Core:
-+ def __init__(self):
-+
-+ self.an_data = AnalyzedData()
-+
-+ self.scatts_dt = ScattPlotsData(self.an_data)
-+ self.scatt_conds_dt = ScattPlotsCondsData(self.an_data)
-+
-+ self.cat_rast_updater = CatRastUpdater(self.scatts_dt, self.an_data, self)
-+
-+ def SetData(self, bands):
-+ self.an_data.Create(bands)
-+
-+ n_bands = len(self.GetBands())
-+
-+ self.scatts_dt.Create(n_bands)
-+ self.scatt_conds_dt.Create(n_bands)
-+
-+ def AddCategory(self, cat_id):
-+ self.scatts_dt.AddCategory(cat_id)
-+ return self.scatt_conds_dt.AddCategory(cat_id)
-+
-+ def DeleteCategory(self, cat_id):
-+ self.scatts_dt.DeleteCategory(cat_id)
-+ self.scatt_conds_dt.DeleteCategory(cat_id)
-+
-+ def CleanUp(self):
-+ self.scatts_dt.CleanUp()
-+ self.scatt_conds_dt.CleanUp()
-+
-+ def GetBands(self):
-+ return self.an_data.GetBands()
-+
-+ def GetScattsData(self):
-+ return self.scatts_dt;
-+
-+ def GetRegion(self):
-+ return self.an_data.GetRegion()
-+
-+ def GetCatRastOut(self, cat_id):
-+ return self.scatts_dt.GetCatRastOut(cat_id)
-+
-+ def AddScattPlot(self, scatt_id):
+ 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)
+-
+
-+ self.scatts_dt.AddScattPlot(scatt_id = scatt_id)
++ 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
+
-+ scatt_conds = self.scatt_conds_dt.GetData({0 : []})
-+ scatts = self.scatts_dt.GetData({0 : [scatt_id]})
+ def OnPlotTypeSelected(self, event):
+ """!Plot type selected"""
+
-+ bands = self.an_data.GetBands()
-+ cats_rasts_out = self.scatts_dt.GetCatsRastsOut()
-+ cats_rasts_in = self.scatts_dt.GetCatsRastsIn()
++ 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()
+
-+ #for cat in scatts.itervalues():
-+ # for scatt_id in cat.itervalues():
-+ # print cat
-+ # scatt_id.values()[0].flush()
-+ # del scatt_id
+ if self.currentCat is None:
+ return
+-
+
-+ returncode, scatts = ComputeScatts(self.an_data.GetRegion(), scatt_conds, bands,
-+ len(self.GetBands()), scatts, cats_rasts_in, cats_rasts_out)
-+ #self.scatts_dt.SetData(scatts)
+ 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()
+-
+
-+ def SetEditCatData(self, cat_id, scatt_id, bbox, value):
++ self.Layout()
+
-+ if self.scatt_conds_dt.AddScattPlot(cat_id, scatt_id) < 0:
-+ return False
+
-+ arr = self.scatt_conds_dt.GetValuesArr(cat_id, scatt_id)
+ def StddevChanged(self):
+ """!Standard deviation multiplier changed, redraw histograms"""
+ if self.plotSwitch.GetSelection() == 0:
+@@ -89,7 +128,7 @@
+ panel.Destroy()
+
+ self.canvasList = []
+-
+
-+ for k, v in bbox.iteritems():
-+ bbox[k] = self._validExtend(v)
-+
-+ arr[bbox['btm_y'] : bbox['up_y'], bbox['btm_x'] : bbox['up_x']] = value
-+ arr.flush()
-+ #del arr
-+
-+ start_time = time.clock()
-+ self.ComputeCatScatts([cat_id])
-+ print "time"
-+ print time.clock() - start_time
-+ return True
-+
-+ def ComputeCatScatts(self, cats_ids):
-+
-+ requested_dt = {}
-+ requested_dt_conds = {}
-+
-+ for c in cats_ids:
-+ requested_dt_conds[c] = self.scatt_conds_dt.GetCatScatts(c)
-+ requested_dt[c] = self.scatts_dt.GetCatScatts(c)
-+
-+ scatt_conds = self.scatt_conds_dt.GetData(requested_dt_conds)
-+ scatts = self.scatts_dt.GetData(requested_dt)
-+
-+ bands = self.an_data.GetBands()
-+
-+ cats_rasts_out = self.scatts_dt.GetCatsRastsOut()
-+ cats_rasts_in = self.scatts_dt.GetCatsRastsIn()
-+
-+ returncode, scatts = ComputeScatts(self.an_data.GetRegion(), scatt_conds, bands,
-+ len(self.GetBands()), scatts, cats_rasts_in, cats_rasts_out)
+ 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.scatts_dt.SetData(scatts)
-+
-+ def CatRastUpdater(self):
-+ return self.cat_rast_updater
-+
-+ def _validExtend(self, val):
-+ #TODO do it general
-+ if val > 255:
-+ val = 255
-+ elif val < 0:
-+ val = 0
-+
-+ return val
-+
-+class CatRastUpdater:
-+
-+ def __init__(self, scatts_dt, an_data, core):
-+ self.scatts_dt = scatts_dt
-+ self.an_data = an_data # TODO may be confusing
-+ self.core = core
-+ self.vectMap = None
-+
-+ def _getBbox(self, points):
-+ bbox = { "maxx" : None,
-+ "maxy" : None,
-+ "minx" : None,
-+ "miny" : None,
-+ }
-+
-+ for pt in points:
-+ if not bbox['maxy']:
-+ bbox['maxy'] = pt[1]
-+ bbox['miny'] = pt[1]
-+ bbox['maxx'] = pt[0]
-+ bbox['minx'] = pt[0]
-+ continue
-+
-+ if bbox['maxy'] < pt[1]:
-+ bbox['maxy'] = pt[1]
-+ elif bbox['miny'] > pt[1]:
-+ bbox['miny'] = pt[1]
-+
-+ if bbox['maxx'] < pt[0]:
-+ bbox['maxx'] = pt[0]
-+ elif bbox['minx'] > pt[0]:
-+ bbox['minx'] = pt[0]
-+
-+ return bbox
-+
-+ def SetVectMap(self, vectMap):
-+ self.vectMap = vectMap
-+
-+ def AddedFeature(self, new_geom, cat):
-+
-+ layer = cat.keys()[0]
-+ cat = cat.values()[0][0]
-+
-+ bbox = self._getBbox(new_geom)
-+ grass_region = self._create_grass_region_env(bbox)
-+
-+ #TODO temp rast
-+ patch_rast = "temp_scatt_plt_patch at class"
-+ self._rasterize(grass_region, layer, cat, patch_rast)
-+
-+ region = self.an_data.GetRegion()
-+
-+ UpdateCatRast(patch_rast, region, self.scatts_dt.GetCatRastIn(cat))
-+
-+ return [cat]
-+
-+ def DeletedAreas(self, old_geoms, old_areas_cats):
-+
-+ updated_cats = []
-+ #for i in range(len(old_geoms)):
-+ # self._updateCatRast(old_geoms[i], old_areas_cats[i], updated_cats)
-+
-+ return updated_cats
-+
-+ def ChangedVertex(self, new_geom, new_areas_cats, old_geom, old_areas_cats):
-+ #TODO possible optimization - bbox only of vertex and its two neighbours
-+
-+ updated_cats = []
-+ self._updateCatRast(old_geom, old_areas_cats, updated_cats)
-+ self._updateCatRast(new_geom, new_areas_cats, updated_cats)
-+
-+ return updated_cats
-+
-+ def findLineDiff(geom1, geom2):
-+
-+ pass
-+ #for pt1 in geom1:
-+
-+ def MovedFeatures(self, old_geoms, old_areas_cats, new_areas_cats, move):
-+ #TODO possible optimization - bbox only of vertex and its two neighbours
-+
-+ updated_cats = []
-+ for i in range(len(old_geoms)):
-+ self._updateCatRast(old_geoms[i], old_areas_cats[i], updated_cats)
-+
-+ new_geom = []
-+ for pt in old_geoms[i]:
-+ new_geom_pt = (pt[0] + move[0], pt[1] + move[1])
-+ new_geom.append(new_geom_pt)
-+
-+ self._updateCatRast(new_geom, new_areas_cats[i], updated_cats)
-+
-+ new_areas_cats = old_geoms[i]
-+
-+ return updated_cats
-+
-+ def _updateCatRast(self, geom, areas_cats, updated_cats):
-+
-+ rasterized_cats = []
-+ for c in range(len(areas_cats)):
-+
-+ if not areas_cats[c]:
-+ continue
-+
-+ layer = areas_cats[c].keys()[0]
-+ cat = areas_cats[c][layer][0]
-+
-+ if cat in rasterized_cats:
-+ continue
-+
-+ rasterized_cats.append(cat)
-+ updated_cats.append(cat)
-+
-+ bbox = self._getBbox(geom)
-+ grass_region = self._create_grass_region_env(bbox)
-+
-+ #TODO hack
-+ patch_rast = "pokus at class"
-+ self._rasterize(grass_region, layer, cat, patch_rast)
-+
-+ region = self.an_data.GetRegion()
-+ UpdateCatRast(patch_rast, region, self.scatts_dt.GetCatRastIn(cat))
-+
-+
-+ def _rasterize(self, grass_region, layer, cat, out_rast):
-+
-+ #TODO different thread may be problem when user edits map
-+ ret, text, msg = RunCommand("v.build",
-+ map = self.vectMap,
-+ getErrorMsg = True,
-+ read = True)#,
-+
-+ #TODO thread problem with env variable remove it!!!!
-+ environs = os.environ.copy()
-+ environs["GRASS_REGION"] = grass_region["GRASS_REGION"]
-+
-+ ret, text, msg = RunCommand("v.to.rast",
-+ input = self.vectMap,
-+ use = "cat",
-+ layer = str(layer),
-+ cat = str(cat),
-+ output = out_rast,
-+ getErrorMsg = True,
-+ read = True,
-+ overwrite = True,
-+ env = environs)
-+ def _create_grass_region_env(self, bbox):
-+
-+ region = self.an_data.GetRegion()
-+ new_region = {}
-+
-+ if bbox["maxy"] <= region["s"]:
-+ return 0
-+ elif bbox["maxy"] >= region["n"]:
-+ new_region["n"] = bbox["maxy"]
-+ else:
-+ new_region["n"] = ceil((bbox["maxy"] - region["s"]) / region["nsres"]) * region["nsres"] + region["s"]
-+
-+ if bbox["miny"] >= region["n"]:
-+ return 0
-+ elif bbox["miny"] <= region["s"]:
-+ new_region["s"] = bbox["miny"]
-+ else:
-+ new_region["s"] = floor((bbox["miny"] - region["s"]) / region["nsres"]) * region["nsres"] + region["s"]
-+
-+ if bbox["maxx"] <= region["w"]:
-+ return 0
-+ elif bbox["maxx"] >= region["e"]:
-+ new_region["e"] = bbox["maxx"]
-+ else:
-+ new_region["e"] = ceil((bbox["maxx"] - region["w"]) / region["ewres"]) * region["ewres"] + region["w"]
-+
-+ if bbox["minx"] >= region["e"]:
-+ return 0
-+ elif bbox["minx"] <= region["w"]:
-+ new_region["w"] = bbox["minx"]
-+ else:
-+ new_region["w"] = floor((bbox["minx"] - region["w"]) / region["ewres"]) * region["ewres"] + region["w"]
-+
-+ #TODO check regions resolutin
-+ new_region["nsres"] = region["nsres"]
-+ new_region["ewres"] = region["ewres"]
-+
-+ return {"GRASS_REGION" : grass.region_env(**new_region)}
-+
-+class AnalyzedData:
-+
-+ def __init__(self):
-+
-+ self.bands = []
-+ self.bands_info = {}
-+
-+ self.region = None
-+
-+ def GetRegion(self):
-+ return self.region
-+
-+ def Create(self, bands):
-+
-+ self.bands = bands
-+ self.region = None
-+
-+ ret, region, msg = RunCommand("g.region",
-+ flags = "gp",
-+ getErrorMsg = True,
-+ read = True)
-+
-+ if ret != 0:
-+ raise GException("g.region failed:\n%s" % msg)
-+
-+
-+ self.bands_info = {}
-+ for b in bands:
-+ self.bands_info[b] = self._getRasterInfo(b)
-+ if self.bands_info[b]["datatype"] != "CELL":
-+ raise GException(_("Raster <%s> is not <CELL> type.") % (b))
-+ #TODO size of raster check
-+
-+ self.region = self._parseRegion(region)
-+
-+ def _getRasterInfo(self, rast):
-+ """
-+ """
-+ ret, out, msg = RunCommand("r.info",
-+ map = rast,
-+ flags = "rg",
-+ getErrorMsg = True,
-+ read = True)
-+
-+ if ret != 0:
-+ raise GException("r.info failed:\n%s" % msg)
-+
-+ out = out.split("\n")
-+ raster_info = {}
-+
-+ for b in out:
-+ if not b.strip():
-+ continue
-+ k, v = b.split("=")
-+ if k == "datatype":
-+ pass
-+ elif k in ['rows', 'cols', 'cells', 'min', 'max']:
-+ v = int(v)
-+ else:
-+ v = float(v)
-+
-+ raster_info[k] = v
-+
-+ return raster_info
-+
-+ def GetBands(self):
-+ return self.bands
-+
-+ def GetBandInfo(self, band_id):
-+ band = self.bands[band_id]
-+ return self.bands_info[band]
-+
-+ def _parseRegion(self, region_str):
-+
-+ region = {}
-+ region_str = region_str.splitlines()
-+
-+ for param in region_str:
-+ k, v = param.split("=")
-+ if k in ["rows", "cols", "cells"]:
-+ v = int(v)
-+ else:
-+ v = float(v)
-+ region[k] = v
-+
-+ return region
-+
-+class ScattPlotsCondsData:
-+
-+ def __init__(self, an_data):
-+
-+ self.an_data = an_data
-+
-+ #TODO
-+ self.max_n_cats = 10
++ self.SetVirtualSize(self.GetBestVirtualSize())
+ self.Layout()
+
+ def UpdatePlots(self, group, currentCat, stats_data):
+@@ -138,7 +177,7 @@
+
+ def UpdateCategory(self, cat):
+ self.currentCat = cat
+-
+
-+ self.dtype = 'uint8'
-+ self.type = 1;
-+ self.CleanUp()
-+
-+ def CleanUp(self):
-+
-+ self.cats = {}
-+
-+ self.n_scatts = -1
-+ self.n_bands = -1
-+
-+ for cat_id in self.cats.keys():
-+ self.DeleteCategory(cat_id)
-+
-+ def Create(self, n_bands):
-+
-+ self.CleanUp()
-+
-+ self.n_scatts = (n_bands - 1) * n_bands / 2;
-+ self.n_bands = n_bands
-+
-+ self.AddCategory(cat_id = 0)
-+
-+ def AddCategory(self, cat_id):
-+
-+ if cat_id not in self.cats.keys():
-+ self.cats[cat_id] = {}
-+ return cat_id
-+ return -1
-+
-+ def DeleteCategory(self, cat_id):
-+
-+ if cat_id not in self.cats.keys():
-+ return False
-+
-+ for scatt in self.cats[cat_id].itervalues():
-+ del scatt['np_vals']
-+
-+ del self.cats[cat_id]
-+
-+ return True
-+
-+ def GetCatScatts(self, cat_id):
-+
-+ if not self.cats.has_key(cat_id):
-+ return False
-+
-+ return self.cats[cat_id].keys()
-+
-+
-+ def AddScattPlot(self, cat_id, scatt_id):
-+
-+ if not self.cats.has_key(cat_id):
-+ return -1
-+
-+ if self.cats[cat_id].has_key(scatt_id):
-+ return 0
-+
-+ b_i = self.GetBandsInfo(scatt_id)
-+
-+ shape = (b_i['b2']['max'] - b_i['b2']['min'] + 1, b_i['b1']['max'] - b_i['b1']['min'] + 1)
-+
-+ np_vals = np.memmap(grass.tempfile(), dtype=self.dtype, mode='w+', shape = shape)
-+ np_vals.flush()
-+
-+ self.cats[cat_id][scatt_id] = {
-+ 'np_vals' : np_vals
-+ }
-+
-+ return 1
-+
-+ def GetBandsInfo(self, scatt_id):
-+ b1, b2 = idScattToidBands(scatt_id, len(self.an_data.GetBands()))
-+
-+ b1_info = self.an_data.GetBandInfo(b1)
-+ b2_info = self.an_data.GetBandInfo(b2)
-+
-+ bands_info = {'b1' : b1_info,
-+ 'b2' : b2_info}
-+
-+ return bands_info
-+
-+ def DeleScattPlot(self, cat_id, scatt_id):
-+
-+ if not self.cats.has_key(cat_id):
-+ return False
-+
-+ if not self.cats[cat_id].has_key(scatt_id):
-+ return False
-+
-+ del self.cats[cat_id][scatt_id]
-+ return True
-+
-+ def GetValuesArr(self, cat_id, scatt_id):
-+
-+ if not self.cats.has_key(cat_id):
-+ return None
-+
-+ if not self.cats[cat_id].has_key(scatt_id):
-+ return None
-+
-+ return self.cats[cat_id][scatt_id]['np_vals']
-+
-+ def GetData(self, requested_dt):
-+
-+ cats = {}
-+ for cat_id, scatt_ids in requested_dt.iteritems():
-+ if not cats.has_key(cat_id):
-+ cats[cat_id] = {}
-+ for scatt_id in scatt_ids:
-+ # if key is missing condition is always True (full scatter plor is computed)
-+ if self.cats[cat_id].has_key(scatt_id):
-+ cats[cat_id][scatt_id] = {'np_vals' : self.cats[cat_id][scatt_id]['np_vals'],
-+ 'bands_info' : self.GetBandsInfo(scatt_id)}
-+
-+ return cats
-+
-+ def SetData(self, cats):
-+
-+ for cat_id, scatt_ids in cats.iteritems():
-+ for scatt_id in scatt_ids:
-+ # if key is missing condition is always True (full scatter plor is computed)
-+ if self.cats[cat_id].has_key(scatt_id):
-+ self.cats[cat_id][scatt_id]['np_vals'] = cats[cat_id][scatt_id]['np_vals']
-+
-+class ScattPlotsData(ScattPlotsCondsData):
-+
-+ def __init__(self, an_data):
-+
-+ self.cats_rasts_out = {}
-+ self.cats_rasts_in = {}
-+ self.scatts_ids = []
-+
-+ ScattPlotsCondsData.__init__(self, an_data)
-+
-+ self.dtype = 'uint32'
-+
-+ #TODO
-+ self.type = 0
-+
-+ def AddCategory(self, cat_id):
-+ cat_id = ScattPlotsCondsData.AddCategory(self, cat_id)
-+ if cat_id < 0:
-+ return cat_id
-+
-+ for scatt_id in self.scatts_ids:
-+ ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
-+
-+ if cat_id == 0:
-+ self.cats_rasts_in[cat_id] = None
-+ self.cats_rasts_out[cat_id] = None
-+ else:
-+ self.cats_rasts_in[cat_id] = grass.tempfile()
-+ self.cats_rasts_out[cat_id] = grass.tempfile()
-+
-+ region = self.an_data.GetRegion()
-+ CreateCatRast(region, self.cats_rasts_in[cat_id])
-+
-+ return cat_id
-+
-+ def DeleteCategory(self, cat_id):
-+
-+ ScattPlotsCondsData.DeleteCategory(self, cat_id)
-+
-+ grass.try_remove(self.cats_rasts_in[cat_id])
-+ del self.cats_rasts_in[cat_id]
-+
-+ grass.try_remove(self.cats_rasts_out[cat_id])
-+ del self.cats_rasts_out[cat_id]
-+
-+ return True
-+
-+ def AddScattPlot(self, scatt_id):
-+
-+ if scatt_id in self.scatts_ids:
-+ return False
-+
-+ self.scatts_ids.append(scatt_id)
-+ for cat_id in self.cats.iterkeys():
-+ ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
-+
-+ return True
-+
-+ def DeleteScatterPlot(self, scatt_id):
-+
-+ if scatt_id not in self.scatts_ids:
-+ return False
-+
-+ self.scatts_ids.remove(scatt_id)
-+
-+ for cat_id in self.cats.iterkeys():
-+ ScattPlotsCondsData.DeleteScattPlot(self, cat_id, scatt_id)
-+
-+ return True
-+
-+ def GetScatt(self, scatt_id):
-+ if scatt_id not in self.scatts_ids:
-+ return False
-+
-+ scatts = {}
-+ for cat_id in self.cats.iterkeys():
-+ scatts[cat_id] = {'np_vals' : self.cats[cat_id][scatt_id]['np_vals'],
-+ 'bands_info' : self.GetBandsInfo(scatt_id)}
-+ return scatts
-+
-+ def CleanUp(self):
-+
-+ ScattPlotsCondsData.CleanUp(self)
-+ for tmp in self.cats_rasts_in:
-+ grass.try_remove(tmp)
-+ for tmp in self.cats_rasts_out:
-+ grass.try_remove(tmp)
-+
-+ self.cats_rasts_out = {}
-+ self.cats_rasts_in = {}
-+
-+ def GetCatRastIn(self, cat_id):
-+ return self.cats_rasts_in[cat_id]
-+
-+ def GetCatRastOut(self, cat_id):
-+ return self.cats_rasts_out[cat_id]
-+
-+ def GetCatsRastsIn(self):
-+ max_cat_id = max(self.cats_rasts_in.keys())
-+
-+ cats_rasts_in = [''] * (max_cat_id + 1)
-+ for i_cat_id, i_rast in self.cats_rasts_in.iteritems():
-+ cats_rasts_in[i_cat_id] = i_rast
-+
-+ return cats_rasts_in
-+
-+ def GetCatsRastsOut(self):
-+ max_cat_id = max(self.cats_rasts_out.keys())
-+
-+ cats_rasts_out = [''] * (max_cat_id + 1)
-+ for i_cat_id, i_rast in self.cats_rasts_out.iteritems():
-+ cats_rasts_out[i_cat_id] = i_rast
-+
-+ return cats_rasts_out
-+
-+#TODO move to utils?
-+def idScattToidBands(scatt_id, n_bands):
-+
-+ n_b1 = n_bands - 1
-+
-+ band_1 = (int) ((2 * n_b1 + 1 - sqrt(((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
-+
-+ return band_1, band_2
-+
-+
-+def idBandsToidScatt(band_1_id, band_2_id, n_bands):
-+
-+ if band_2_id < band_1_id:
-+ tmp = band_1
-+ band_1_id = band_2_id
-+ band_2_id = tmp
-+
-+ n_b1 = n_bands - 1
-+
-+ scatt_id = (band_1_id * (2 * n_b1 + 1) - band_1_id * band_1_id) / 2 + band_2_id - band_1_id - 1
-+
-+ return scatt_id
-+
+ 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,133 @@
+@@ -0,0 +1,134 @@
+"""!
+ at package scatt_plot.gthreading
+
@@ -1481,6 +548,8 @@
+
+ ret = None
+ exception = None
++
++ #to
+ #try:
+ ret = vars()['callable'](*args, **kwds)
+ #except Exception as e:
@@ -1490,7 +559,6 @@
+
+ time.sleep(.1)
+
-+
+ if self.receiver:
+ event = wxCmdDone(type = 'cmd',
+ kwds = kwds,
@@ -1509,11 +577,11 @@
+ if self.requestQ.empty():
+ self._want_abort_all = False
\ No newline at end of file
-Index: gui/wxpython/scatt_plot/dialogs.py
+Index: gui/wxpython/scatt_plot/dialogs_iclass.py
===================================================================
---- gui/wxpython/scatt_plot/dialogs.py (revision 0)
-+++ gui/wxpython/scatt_plot/dialogs.py (working copy)
-@@ -0,0 +1,612 @@
+--- 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
+
@@ -1532,122 +600,127 @@
+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 core import globalvar
++from core.gcmd import GException, GError, RunCommand
+
+from gui_core.gselect import Select
-+from gui_core.widgets import GNotebook
+
+from scatt_plot.controllers import ScattsManager
-+from scatt_plot.toolbars import MainToolbar, CategoriesToolbar
-+from scatt_plot.sc_pl_core import Core, idBandsToidScatt
-+from scatt_plot.plots import ScatterPlotWidget
++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 ScattPlotMainDialog(wx.Dialog):
++class IClassScatterPlotsPanel(wx.Panel):
+ def __init__(self, parent, giface, iclass_mapwin = None,
-+ id = wx.ID_ANY, title = _("GRASS GIS Interactive Scatter Plot Tool"),
-+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-+
-+ wx.Dialog.__init__(self, parent, id, style=style, title = title, **kwargs)
-+ self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
++ id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+
-+ #TODO remove iclass parameter
++ #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)
-+
-+ self.mainPanel = wx.Panel(parent=self)
-+ self.notebook = GNotebook(parent = self.mainPanel,
-+ style = FN.FNB_FANCY_TABS | FN.FNB_BOTTOM |
-+ FN.FNB_NO_X_BUTTON)
++ self.toolbars['mainToolbar'] = MainToolbar(parent = self, scatt_mgr = self.scatt_mgr)
++ self._createCategoryPanel(self)
+
-+ # Fancy gui
-+ self._mgr = wx.aui.AuiManager(self)
-+ self._addPanes()
-+ self._mgr.Update()
++ self.plot_panel = IClassPlotPanel(self, self.scatt_mgr)
+
-+ self._createCategoryPage()
-+
-+ self.edit_cat_tools = {
-+ 'editCatAdd' : {
-+ 'toggle' : False,
-+ 'type' : 'add'
-+ },
-+ 'editCatRemove' : {
-+ 'toggle' : False,
-+ 'type' : 'remove'
-+ }
-+ }
-+ self._doLayout()
-+ self.Bind(wx.EVT_CLOSE, self.OnCloseDialog)
++ 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)
+
-+ dlgSize = (220, 400)
-+ self.SetMinSize(dlgSize)
-+ self.SetInitialSize(dlgSize)
++
++ #self.SetSashGravity(0.5)
++ #self.SplitHorizontally(self.head_panel, self.plot_panel, -50)
++ self.Layout()
++ #self.SetAutoLayout(1)
+
-+ #fix goutput's pane size (required for Mac OSX)
-+ #if self.gwindow:
-+ # self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
++ def NewScatterPlot(self, scatt_id):
++ return self.plot_panel.NewScatterPlot(scatt_id)
+
-+ def _doLayout(self):
++ 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()
+
-+ sizer = wx.BoxSizer(wx.VERTICAL)
++ def _createCategoryPanel(self, parent):
++ self.catsPanel = wx.Panel(parent = parent)
++ self.cats_list = CategoryListCtrl(parent = self.catsPanel,
++ cats_mgr = self.scatt_mgr.GetCategoriesManager())
+
-+ sizer.Add(item = self.notebook, proportion = 1,
-+ flag = wx.EXPAND)
++ self.catsPanel.SetMaxSize((-1, 150))
+
-+ self.mainPanel.SetSizer(sizer)
++ 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)
+
-+ sizer.Fit(self)
-+ self.Layout()
++ catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND | wx.ALL)
++ self.catsPanel.SetSizer(catsSizer)
+
-+ #TODO split to panel?
-+ def _createCategoryPage(self):
-+ catsPanel = wx.Panel(parent = self)
+
++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.notebook.AddPage(page = catsPanel,
-+ text=_('Categories'),
-+ name = 'categories')
++ self.scatt_mgr = scatt_mgr
+
-+ self.cats_list = CategoryListCtrl(parent = catsPanel,
-+ cats_mgr = self.scatt_mgr.GetCategoriesManager())
-+ self.toolbars['catsList'] = CategoriesToolbar(parent = catsPanel,
-+ cats_list = self.cats_list,
-+ scatts_dlg = self)
++ self.mainPanel = wx.Panel(parent = self, id = wx.ID_ANY)
+
-+ AnalysisSizer = wx.BoxSizer(wx.VERTICAL)
++ #self._createCategoryPanel()
++ # Fancy gui
++ self._mgr = aui.AuiManager(self.mainPanel)
++ #self._mgr.SetManagedWindow(self)
+
-+ catsSizer = wx.BoxSizer(wx.VERTICAL)
++ self._mgr.Update()
+
-+ catsSizer.Add(item = self.toolbars['catsList'], proportion = 0)
-+ catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND)
++ self._doLayout()
++ self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
+
-+ catsPanel.SetSizer(catsSizer)
++ 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 _addPanes(self):
-+ """!Adds toolbar pane and pane with tabs"""
-+ self._mgr.AddPane(self.toolbars['mainToolbar'],
-+ wx.aui.AuiPaneInfo().
-+ Name("pointlisttools").Caption(_("Point cats_list toolbar")).
-+ ToolbarPane().Top().Row(0).
-+ Dockable(False).
-+ CloseButton(False).Layer(0))
++ def _doLayout(self):
+
-+ self._mgr.AddPane(self.mainPanel,
-+ wx.aui.AuiPaneInfo().
-+ Name("tabs").CaptionVisible(visible = False).
-+ Center().
-+ Dockable(False).
-+ CloseButton(False).Layer(0))
++ 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()
@@ -1656,91 +729,202 @@
+ def OnSettings(self, event):
+ pass
+
-+ def OnSetData(self, event):
++ def NewScatterPlot(self, scatt_id):
++ #TODO needs to be resolved (should be in this class)
+
-+ dlg = SetDataDialog(parent=self)
++ scatt = ScatterPlotWidget(parent = self.mainPanel,
++ scatt_mgr = self.scatt_mgr,
++ scatt_id = scatt_id)
+
-+ if dlg.ShowModal() == wx.ID_OK:
-+ bands = dlg.GetBands()
-+ self.scatt_mgr.SetData(bands)
-+
-+ dlg.Destroy()
++ 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()
+
-+ def NewScatterPlot(self, scatt_id):
-+ #TODO needs to be resolved (should be in this class)
-+ scatt_dlg = ScatterPlotDialog(parent = self, scatt_mgr = self.scatt_mgr, scatt_id = scatt_id)
-+ return scatt_dlg.GetPlot()
++ return scatt
+
-+ def OnSettings(self, event):
-+ pass
++ def GetScattMgr(self):
++ return self.scatt_mgr
+
-+ def OnAddScattPl(self, event):
++class CategoryListCtrl(wx.ListCtrl,
++ listmix.ListCtrlAutoWidthMixin,
++ listmix.TextEditMixin):
+
-+ bands = self.scatt_mgr.GetBands()
-+ if not bands:
-+ GError(_('No data set for scatter plot.'))
-+ return
++ def __init__(self, parent, cats_mgr, id = wx.ID_ANY):
+
-+ dlg = AddScattPlotDialog(parent = self, bands = bands)
++ 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)
+
-+ if dlg.ShowModal() == wx.ID_OK:
-+ self.scatt_mgr.AddScattPlot(dlg.GetScattId())
++ self.cats_mgr = cats_mgr
++ self.SetItemCount(len(self.cats_mgr.GetCategories()))
++
++ self.rightClickedItemIdx = wx.NOT_FOUND
+
-+ dlg.Destroy()
++ listmix.ListCtrlAutoWidthMixin.__init__(self)
+
-+ def EditCatAdd(self):
-+ self._setEditCat(tool_name = 'editCatAdd')
++ 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 EditCatRemove(self):
-+ self._setEditCat(tool_name = 'editCatRemove')
++ def Update(self, **kwargs):
++ self.SetItemCount(len(self.cats_mgr.GetCategories()))
++ self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
+
-+ def _setEditCat(self, tool_name):
++ 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)
+
-+ if self.edit_cat_tools[tool_name]['toggle'] == False:
-+
-+ for i_tool_name in self.edit_cat_tools.iterkeys():
-+ if i_tool_name == tool_name:
-+ continue
++ self.Select(row)
++
++ def Populate(self, columns):
++ for i, col in enumerate(columns):
++ self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
+
-+ self.edit_cat_tools[i_tool_name]['toggle'] = False
++ self.SetColumnWidth(0, 100)
++ self.SetColumnWidth(1, 100)
++
++ def AddCategory(self):
+
-+ toolbar = self.toolbars['catsList']
-+ toolbar.ToggleTool(vars(toolbar)[i_tool_name], False)
++ 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]
+
-+ self.edit_cat_tools[tool_name]['toggle'] = True
-+ self.scatt_mgr.EditCat(edit_type = self.edit_cat_tools[tool_name]['type'])
-+ return
++ cats.append(cat_id)
+
-+ self.scatt_mgr.EditCat(edit_type = None)
-+ self.edit_cat_tools[tool_name]['toggle'] = False
++ 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 GetScattMgr(self):
-+ return self.scatt_mgr
++ 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
+
-+class SetDataDialog(wx.Dialog):
++ if currentCol == 1:
++ dlg = wx.ColourDialog(self)
++ dlg.GetColourData().SetChooseFull(True)
+
-+ def __init__(self, parent, id = wx.ID_ANY):
++ 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)
+
-+ wx.Dialog.__init__(self, parent, title = ("Select imagery group "), id = id)
++ 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]
+
-+ self.bands = []
++ 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()
-+ self.group.SetValue("B_sk")
+
+ def _createWidgets(self):
+
+ self.labels = {}
+ self.params = {}
+
-+ self.group_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Name of raster group for input data:"))
++ self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
+
-+ self.group = Select(parent = self, type = 'group',
-+ size = globalvar.DIALOG_GSELECT_SIZE)
++ 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)
+
@@ -1755,9 +939,12 @@
+
+ regionSizer = wx.BoxSizer(wx.HORIZONTAL)
+
-+ dialogSizer.Add(item = self._addSelectSizer(title = self.group_label,
-+ sel = self.group))
++ 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)
+
@@ -1801,10 +988,6 @@
+
+ return selSizer
+
-+ def GetBands(self):
-+
-+ return self.bands
-+
+ def OnClose(self, event):
+ """!Close dialog
+ """
@@ -1815,30 +998,51 @@
+ def OnOk(self, event):
+ """!
+ """
-+ ret, stdout, err_msg = RunCommand("i.group",
-+ getErrorMsg = True,
-+ read = True,
-+ quiet = True,
-+ group = self.group.GetValue().strip(),
-+ flags = 'g')
++ band_1 = self.band_1_ch.GetSelection()
++ band_2 = self.band_2_ch.GetSelection()
+
-+ if ret != 0:
-+ GError("%s module failed:\n%s" % ("<i.group>", err_msg))
++
++ 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.bands = stdout.split('\n')
++ self.scatt_id = idBandsToidScatt(band_1, band_2, len(self.bands))
+
-+ for band in self.bands[:]:
-+ if not band:
-+ self.bands.remove(band)
-+
+ event.Skip()
+
-+ #TODO catch event or...
-+ def GetSelectedCatId(self):
-+
-+ return self.cats_list.GetSelectedCatId()
++ 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):
@@ -1961,171 +1165,118 @@
+
+ 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
+
-+class ScatterPlotDialog(wx.Dialog):
-+ def __init__(self, parent, scatt_mgr, scatt_id,
-+ id = wx.ID_ANY, title = _("Test plot"),
-+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-+
-+ wx.Dialog.__init__(self, parent, id, style=style, title = title, **kwargs)
-+ self.scatt = ScatterPlotWidget(parent = self,
-+ scatt_mgr = scatt_mgr,
-+ scatt_id = scatt_id)
++ at brief Scatter plot - toolbars
+
-+ def GetPlot(self):
-+ return self.scatt
++Classes:
++ - toolbars::MainToolbar
+
-+ def _doLayout(self):
-+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
-+ self.main_sizer.Add(self.self)
++(C) 2013 by the GRASS Development Team
+
-+ self.panel.SetSizer(self.main_sizer)
-+ self.main_sizer.Fit(self)
-+
-+ def OnPlotClosed(self, scatt_id):
-+ self.Destroy()
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
+
-+class CategoryListCtrl(wx.ListCtrl,
-+ listmix.ListCtrlAutoWidthMixin,
-+ listmix.TextEditMixin):
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
+
-+ 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 = ((_('Category name'), 'name'),
-+ (_('Color'), 'color'))
-+ self.Populate(columns = self.columns)
-+
-+ self.cats_mgr = cats_mgr
-+ self.SetItemCount(len(self.cats_mgr.GetCategories()))
++import wx
+
-+ self.rightClickedItemIdx = wx.NOT_FOUND
-+
-+ listmix.ListCtrlAutoWidthMixin.__init__(self)
++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
+
-+ 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()))
++class MainToolbar(BaseToolbar):
++ """!Main toolbar
++ """
++ def __init__(self, parent, scatt_mgr):
++ BaseToolbar.__init__(self, parent)
++ self.scatt_mgr = scatt_mgr
+
-+ 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.InitToolbar(self._toolbarData())
+
-+ self.Select(row)
-+
-+ def Populate(self, columns):
-+ for i, col in enumerate(columns):
-+ self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
++ # realize the toolbar
++ self.Realize()
+
-+ self.SetColumnWidth(0, 100)
-+ self.SetColumnWidth(1, 100)
-+
-+ def AddCategory(self):
++ def _toolbarData(self):
+
-+ self.cats_mgr.addedCategory.disconnect(self.Update)
-+ cat_id = self.cats_mgr.AddCategory()
-+ self.cats_mgr.addedCategory.connect(self.Update)
++ 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'))
++ }
+
-+ 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)
++ 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),
++ ))
+
-+ 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):
-+ self.cats_mgr.SetSelectedCat(event.GetIndex() + 1)
++ def GetToolId(self, toolName): #TODO can be useful in base
+
-+ event.Skip()
++ return vars(self)[toolName]
+
-+ 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 SetPloltsMode(self, event, tool_name):
+
-+ def OnEdit(self, event):
-+ currentItem = event.m_itemIndex
-+ currentCol = event.m_col
++ #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]
+
-+ if currentCol == 1:
-+ dlg = wx.ColourDialog(self)
-+ dlg.GetColourData().SetChooseFull(True)
++ self.ToggleTool(i_tool_id, False)
++ self.scatt_mgr.SetPlotsMode(mode = tool_name)
++ return
+
-+ 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
++ 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)
@@ -2150,9 +1301,9 @@
+
+import wx
+
-+from icons.icon import MetaIcon
++from icons.icon import MetaIcon
+from gui_core.toolbars import BaseToolbar, BaseIcons
-+from core.gcmd import RunCommand
++from core.gcmd import RunCommand
+
+class MainToolbar(BaseToolbar):
+ """!Main toolbar
@@ -2242,7 +1393,7 @@
===================================================================
--- gui/wxpython/scatt_plot/core_c.py (revision 0)
+++ gui/wxpython/scatt_plot/core_c.py (working copy)
-@@ -0,0 +1,227 @@
+@@ -0,0 +1,226 @@
+"""!
+ at package scatt_plot.scatt_plot
+
@@ -2323,8 +1474,8 @@
+ pointer(scatt_conds_c),
+ pointer(char_bands),
+ n_bands,
++ pointer(char_cats_rasts_in),
+ pointer(sccats_c),
-+ pointer(char_cats_rasts_in),
+ pointer(char_cats_rasts_out))
+
+ I_sc_free_cats(pointer(sccats_c))
@@ -2430,14 +1581,13 @@
+ cell_head = _regionToCellHead(region)
+
+
-+ cat_rast
+ I_insert_patch_to_cat_rast(patch_rast,
-+ pointer(cell_head),
-+ cat_rast)
++ pointer(cell_head),
++ cat_rast)
+
+ #print re
+ #output_queue.put((ret, scatts))
-+ #return (ret, scatts)
++ #return (ret, scatts)
+
+"""
+class A:
@@ -2474,9 +1624,10 @@
===================================================================
--- gui/wxpython/scatt_plot/__init__.py (revision 0)
+++ gui/wxpython/scatt_plot/__init__.py (working copy)
-@@ -0,0 +1,8 @@
+@@ -0,0 +1,9 @@
+all = [
+ 'dialogs',
++ 'gui_iclass',
+ 'gthreading',
+ 'plots',
+ 'sc_pl_core',
@@ -2487,7 +1638,7 @@
===================================================================
--- gui/wxpython/scatt_plot/plots.py (revision 0)
+++ gui/wxpython/scatt_plot/plots.py (working copy)
-@@ -0,0 +1,199 @@
+@@ -0,0 +1,223 @@
+"""!
+ at package scatt_plot.dialogs
+
@@ -2505,6 +1656,7 @@
+import wx
+import numpy as np
+import random
++
+try:
+ haveMatPlot = True
+ import matplotlib
@@ -2519,7 +1671,7 @@
+class ScatterPlotWidget(wx.Panel):
+ def __init__(self, parent, scatt_id, scatt_mgr,
+ id = wx.ID_ANY):
-+
++
+ wx.Panel.__init__(self, parent, id)
+
+ self.parent = parent
@@ -2533,7 +1685,29 @@
+ self.cidpress = None
+ self.cidrelease = None
+
-+ def StartCategoryEdit(self):
++ self.SetSize((200, 100))
++ self.Layout()
++
++ def SetMode(self, mode):
++ self._deactivateMode()
++
++ if mode == 'zoom':
++ self.toolbar.zoom()
++ elif mode == 'pan':
++ self.toolbar.pan()
++ elif mode in ["add", "remove"]:
++ self._startCategoryEdit()
++
++ def _deactivateMode(self):
++
++ if self.toolbar._active == "PAN":
++ self.toolbar.pan()
++ elif self.toolbar._active == "ZOOM":
++ self.toolbar.zoom()
++
++ self._stopCategoryEdit()
++
++ def _startCategoryEdit(self):
+ 'connect to all the events we need'
+ self.cidpress = self.canvas.mpl_connect(
+ 'button_press_event', self.OnPress)
@@ -2572,7 +1746,7 @@
+
+ self.scatt_mgr.SetEditCatData(self.scatt_id, bbox)
+
-+ def StopCategoryEdit(self):
++ def _stopCategoryEdit(self):
+ 'disconnect all the stored connection ids'
+
+ if self.cidpress:
@@ -2587,7 +1761,7 @@
+ # 5x4 inches, 100 dots-per-inch
+ #
+ self.dpi = 100
-+ self.fig = Figure((5.0, 4.0), dpi=self.dpi)
++ self.fig = Figure((1.0, 1.0), dpi=self.dpi)
+ self.canvas = FigCanvas(self, -1, self.fig)
+
+ # Since we have only one plot, we can use add_axes
@@ -2595,8 +1769,8 @@
+ # configuration tool in the navigation toolbar wouldn't
+ # work.
+ #
-+ self.axes = self.fig.add_subplot(111)
-+
++ #elf.axes = self.fig.add_subplot(111)
++ self.axes = self.fig.add_axes([0,0,1,1])
+ # Bind the 'pick' event for clicking on one of the bars
+ #
+ self.canvas.mpl_connect('button_press_event', self.on_pick)
@@ -2605,14 +1779,14 @@
+ # Create the navigation toolbar, tied to the canvas
+ #
+ self.toolbar = NavigationToolbar(self.canvas)
++ #print vars(self.toolbar)
++ #print [method for method in dir(self.toolbar) if callable(getattr(self.toolbar, method))]
+
+ def _doLayout(self):
+
+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
+ self.main_sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
-+ self.main_sizer.Add(self.toolbar, 0, wx.EXPAND)
-+ self.main_sizer.AddSpacer(10)
-+
++ #self.main_sizer.Add(self.toolbar, 0, wx.EXPAND)
+ self.SetSizer(self.main_sizer)
+ self.main_sizer.Fit(self)
+
@@ -2646,14 +1820,15 @@
+
+ #self.axes.set_xlim((0, 270))
+ #self.axes.set_ylim((0, 270))
-+ np.savetxt("/home/ostepok/Desktop/data.txt", scatt['np_vals'], fmt = '%d')
++ #np.savetxt("/home/ostepok/Desktop/data.txt", scatt['np_vals'], fmt = '%d')
+
+
+ #TODO needs optimization
+ img = self.axes.imshow(masked_cat, cmap = cmap,
+ origin = 'lower',
+ extent = (b1_i['min'] - 0.5, b1_i['max'] + 0.5, b2_i['min'] - 0.5, b2_i['max'] + 0.5),
-+ interpolation='nearest')
++ interpolation='nearest',
++ aspect = "auto")
+
+ self.canvas.draw()
+
@@ -2688,55 +1863,1253 @@
+ self.parent.OnPlotClosed(self.scatt_id)
+ self.Destroy()
\ No newline at end of file
-Index: gui/wxpython/mapdisp/toolbars.py
+Index: gui/wxpython/scatt_plot/controllers.py
===================================================================
---- gui/wxpython/mapdisp/toolbars.py (revision 57336)
-+++ gui/wxpython/mapdisp/toolbars.py (working copy)
-@@ -243,7 +243,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)))
-
- def OnDecoration(self, event):
- """!Decorations overlay menu
-Index: gui/wxpython/mapdisp/frame.py
-===================================================================
---- gui/wxpython/mapdisp/frame.py (revision 57336)
-+++ gui/wxpython/mapdisp/frame.py (working copy)
-@@ -207,6 +207,7 @@
- #
- self.dialogs = {}
- self.dialogs['attributes'] = None
-+ self.dialogs['scatt_plot'] = None
- self.dialogs['category'] = None
- self.dialogs['barscale'] = None
- self.dialogs['legend'] = None
-@@ -1301,6 +1302,19 @@
- """!Returns toolbar with zooming tools"""
- return self.toolbars['map']
-
-+ def OnScatterplot2(self, event):
-+ """!Init interactive scatterplot tools
+--- gui/wxpython/scatt_plot/controllers.py (revision 0)
++++ gui/wxpython/scatt_plot/controllers.py (working copy)
+@@ -0,0 +1,563 @@
++"""!
++ at package scatt_plot.controllers
++
++ at brief Controller layer for scatter plot tool.
++
++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
++
++#TODO
++import wx
++
++from core.gcmd import GException, GError, RunCommand
++
++from scatt_plot.sc_pl_core import Core, idBandsToidScatt
++from scatt_plot.plots import haveMatPlot
++
++from scatt_plot.dialogs import AddScattPlotDialog
++from scatt_plot.gthreading import gThread
++from core.gconsole import EVT_CMD_DONE
++from grass.pydispatch.signal import Signal
++
++class ScattsManager(wx.EvtHandler):
++ def __init__(self, guiparent, giface, iclass_mapwin):
++ #TODO remove iclass parameter
++ if not haveMatPlot:
++ raise GException(_("The interactive scatter plot tool needs \"Matplotlib\" package to be installed."))
++
++ wx.EvtHandler.__init__(self)
++ self.giface = giface
++ self.mapDisp = giface.GetMapDisplay()
++
++ if iclass_mapwin:
++ self.mapWin = iclass_mapwin
++ else:
++ self.mapWin = giface.GetMapWindow()
++
++ self.guiparent = guiparent
++
++ self.show_add_scatt_plot = False
++
++ self.core = Core()
++ self.scatts_dt = self.core.GetScattsData()
++
++ self.cats_mgr = CategoriesManager(self, self.core)
++
++ self.thread = gThread(self);
++
++ self.scatt_plts = {}
++ self.added_cats_rasts = {}
++
++ self.cats_to_update = []
++
++ self.plot_mode = None
++
++ self.data_set = False
++
++ if iclass_mapwin:
++ self.mapWin_conn = MapWinConnection(self, self.mapWin, self.core.CatRastUpdater())
++ self.iclass_conn = IClassConnection(self, iclass_mapwin.parent, self.cats_mgr)
++ else:
++ self.mapWin_conn = None
++ self.iclass_conn = None
++
++ self.tasks_pids = {
++ 'add_scatt' : [],
++ 'set_data' : -1,
++ 'set_data_add' : -1,
++ 'set_edit_cat_data' : -1,
++ 'mapwin_conn' : [],
++ 'render_plots' : -1
++ }
++
++ self.Bind(EVT_CMD_DONE, self.OnThreadDone)
++
++ def SetData(self, bands):
++ self.data_set = False
++
++ if self.show_add_scatt_plot:
++ self.tasks_pids['set_data_add'] = self.thread.GetId()
++ else:
++ self.tasks_pids['set_data'] = self.thread.GetId()
++
++ self.thread.Run(callable = self.core.SetData, bands = bands)
++
++ #for i in range(1):
++ # self.AddScattPlot(i)
++
++ def SetDataDone(self, event):
++
++ self.data_set = True
++ self.cats_mgr.InitCoreCats()
++
++ def OnOutput(self, event):
++ """!Print thread output according to debug level.
+ """
-+ if self.dialogs['scatt_plot']:
-+ self.dialogs['scatt_plot'].Raise()
++ print event.text
++
++ def GetBands(self):
++ return self.core.GetBands()
++
++ def AddScattPlot(self):
++ if not self.data_set and self.iclass_conn:
++ self.show_add_scatt_plot = True
++ self.iclass_conn.SetData()
++ self.show_add_scatt_plot = False
+ return
++ if not self.data_set:
++ GError(_('No data set.'))
++ return
+
-+ from scatt_plot.dialogs import ScattPlotMainDialog
-+ self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface)
++ dlg = AddScattPlotDialog(parent = self.guiparent, bands = self.core.GetBands())
++
++ if dlg.ShowModal() == wx.ID_OK:
++ self._addScattPlot(dlg.GetScattId())
+
-+ self.dialogs['scatt_plot'].CenterOnScreen()
-+ self.dialogs['scatt_plot'].Show()
++ dlg.Destroy()
+
- def OnVNet(self, event):
- """!Dialog for v.net* modules
- """
++ def _addScattPlot(self, scatt_id):
++
++ self.tasks_pids['add_scatt'].append(self.thread.GetId())
++
++ self.thread.Run(callable = self.core.AddScattPlot, scatt_id = scatt_id)
++
++ def RenderScattPlts(self):
++
++ cats_attrs = self.cats_mgr.GetCategoriesAttrs()
++ for scatt_id, scatt in self.scatt_plts.iteritems():
++ scatt_dt = self.scatts_dt.GetScatt(scatt_id)
++ scatt.Plot(scatt_dt, cats_attrs)
++
++
++ def AddScattPlotDone(self, event):
++
++ scatt_id = event.kwds['scatt_id']
++
++ #TODO guiparent - not very good
++ self.scatt_plts[scatt_id] = self.guiparent.NewScatterPlot(scatt_id = scatt_id)
++
++ if self.plot_mode:
++ self.scatt_plts[scatt_id].SetMode(self.plot_mode)
++
++ scatt_dt = self.scatts_dt.GetScatt(scatt_id)
++
++ cats_attrs = self.cats_mgr.GetCategoriesAttrs()
++
++ self.scatt_plts[scatt_id].Plot(scatt_dt, cats_attrs)
++ #for scatt in scatt_dt.itervalues():
++ # del scatt
++ self.scatt_plts[scatt_id].GetParent().Show()
++
++ def CleanUp(self):
++ self.core.CleanUp()
++
++ for scatt_id, scatt in self.scatt_plts.items():
++ scatt.CleanUp()
++ del self.scatt_plts[scatt_id]
++
++ def OnThreadDone(self, event):
++
++ if event.exception:
++ GError(str(event.exception))
++ return
++
++ if event.pid in self.tasks_pids['mapwin_conn']:
++ self.tasks_pids['mapwin_conn'].remove(event.pid)
++ updated_cats = event.ret
++
++ for cat in updated_cats:
++ if cat not in self.cats_to_update:
++ self.cats_to_update.append(cat)
++
++ if not self.tasks_pids['mapwin_conn']:
++ self.tasks_pids['render_plots'] = self.thread.GetId()
++ self.thread.Run(callable = self.core.ComputeCatsScatts,
++ cats_ids = self.cats_to_update[:])
++ del self.cats_to_update[:]
++
++ return
++
++ if self.tasks_pids['render_plots'] == event.pid:
++ #TODO how to put it to the thread - kils gui
++ self.RenderScattPlts()
++ return
++
++ if event.pid in self.tasks_pids['add_scatt']:
++ self.AddScattPlotDone(event)
++ return
++
++ if self.tasks_pids['set_data'] == event.pid:
++ self.SetDataDone(event)
++ return
++
++ if self.tasks_pids['set_data_add'] == event.pid:
++ self.SetDataDone(event)
++ self.AddScattPlot()
++ return
++
++ if self.tasks_pids['set_edit_cat_data'] == event.pid:
++ self.SetEditCatDataDone(event)
++ return
++
++ def SetPlotsMode(self, mode):
++
++ self.plot_mode = mode
++
++ for scatt in self.scatt_plts.itervalues():
++ scatt.SetMode(mode)
++
++ def SetEditCatData(self, scatt_id, bbox):
++
++ value = 1
++ if self.plot_mode == 'remove':
++ value = 0
++
++ self.tasks_pids['set_edit_cat_data'] = self.thread.GetId()
++
++ sel_cat_id = self.cats_mgr.GetSelectedCat()
++
++ if not sel_cat_id:
++ dlg = wx.MessageDialog(parent = self.guiparent,
++ message = _("In order to select arrea in scatter plot, "
++ "you have to select class first.\n\n"
++ "There is no class yet, "
++ "do you want to create one?"),
++ caption = _("No class selected"),
++ style = wx.YES_NO)
++ if dlg.ShowModal() == wx.ID_YES:
++ self.iclass_conn.EmptyCategories()
++ return
++
++ self.thread.Run(callable = self.core.SetEditCatData,
++ scatt_id = scatt_id,
++ cat_id = sel_cat_id,
++ bbox = bbox,
++ value = value)
++
++ def SetEditCatDataDone(self, event):
++
++ if event.exception:
++ GError(_("Error occured during computation of scatter plot category:\n%s") , parent = self.guiparent, showTraceback = False)
++
++ self.RenderScattPlts()
++
++ cat_id = event.kwds["cat_id"]
++
++ cat_rast = self.core.GetCatRast(cat_id)
++
++
++ if cat_rast not in self.added_cats_rasts.values():
++
++ cats_attrs = self.cats_mgr.GetCategoryAttrs(cat_id)
++
++
++ region = self.core.GetRegion()
++ ret, err_msg = RunCommand('r.region',
++ map = cat_rast,
++ getErrorMsg = True,
++ n = "%f" % region['n'],
++ s = "%f" % region['s'],
++ e = "%f" % region['e'],
++ w = "%f" % region['w'],
++ )
++
++ region = self.core.GetRegion()
++ ret, err_msg = RunCommand('r.colors',
++ map = cat_rast,
++ rules = "-",
++ stdin = "1 %s" % cats_attrs["color"],
++ getErrorMsg = True)
++
++ if ret != 0:
++ GError(_("r.region failed\n%s" % err_msg))
++
++ self.mapWin.Map.AddLayer(ltype = "raster", name = "cat_%d" % cat_id, render = True,
++ command = ["d.rast", "map=%s" % cat_rast, "values=1"])
++
++
++ if ret != 0:
++ GError(_("r.region failed\n%s" % err_msg))
++
++ self.added_cats_rasts[cat_id] = cat_rast
++
++ self.giface.updateMap.emit()
++
++ def DigitDataChanged(self, vectMap, digit):
++
++ if self.mapWin_conn:
++ self.mapWin_conn.DigitDataChanged(vectMap, digit)
++ return 1
++ else:
++ return 0
++
++ def GetCategoriesManager(self):
++ return self.cats_mgr
++
++class CategoriesManager:
++
++ def __init__(self, scatt_mgr, core):
++
++ self.core = core
++ self.scatt_mgr = scatt_mgr
++
++ self.cats = {}
++ self.cats_ids = []
++
++ self.sel_cat_id = None
++
++ self.initialized = Signal('CategoriesManager.initialized')
++ self.setCategoryAttrs = Signal('CategoriesManager.setCategoryAttrs')
++ self.deletedCategory = Signal('CategoriesManager.deletedCategory')
++ self.addedCategory = Signal('CategoriesManager.addedCategory')
++
++ def Clear(self):
++
++ self.cats.clear()
++ del self.cats_ids[:]
++
++ self.sel_cat_id = None
++
++ def InitCoreCats(self):
++ if self.scatt_mgr.data_set:
++ for cat_id in self.cats_ids:
++ self.core.AddCategory(cat_id)
++
++ def AddCategory(self, cat_id = None, name = None, color = None):
++
++ if cat_id is None:
++ if self.cats_ids:
++ cat_id = max(self.cats_ids) + 1
++ else:
++ cat_id = 1
++
++ if self.scatt_mgr.data_set:
++ ret = self.core.AddCategory(cat_id)
++ if ret < 0: #TODO
++ return -1;
++
++ self.cats[cat_id] = {
++ 'name' : _('Category %s' % cat_id ),
++ 'color' : "0:0:0"
++ }
++ self.cats_ids.append(cat_id)
++
++ if name is not None:
++ self.cats[cat_id]["name"] = name
++
++ if color is not None:
++ self.cats[cat_id]["color"] = color
++
++ self.addedCategory.emit(cat_id = cat_id,
++ name = self.cats[cat_id]["name"],
++ color = self.cats[cat_id]["color"] )
++ return cat_id
++
++ def SetCategoryAttrs(self, cat_id, attrs_dict):
++ for k, v in attrs_dict.iteritems():
++ self.cats[cat_id][k] = v
++
++ self.setCategoryAttrs.emit(cat_id = cat_id, attrs_dict = attrs_dict)
++
++ def DeleteCategory(self, cat_id):
++
++ if self.scatt_mgr.data_set:
++ self.core.DeleteCategory(cat_id)
++ del self.cats[cat_id]
++ self.cats_ids.remove(cat_id)
++
++ self.deletedCategory.emit(cat_id = cat_id)
++
++ #TODO emit event?
++ def SetSelectedCat(self, cat_id):
++ self.sel_cat_id = cat_id
++
++ def GetSelectedCat(self):
++ return self.sel_cat_id
++
++ def GetCategoryAttrs(self, cat_id):
++ #TODO is mutable
++ return self.cats[cat_id]
++
++ def GetCategoriesAttrs(self):
++ #TODO is mutable
++ return self.cats
++
++ def GetCategories(self):
++ return self.cats_ids[:]
++
++class MapWinConnection:
++ def __init__(self, scatt_mgr, mapWin, scatt_rast_updater):
++ self.mapWin = mapWin
++ self.vectMap = None
++ self.scatt_rast_updater = scatt_rast_updater
++ self.scatt_mgr = scatt_mgr
++ self.cats_mgr = scatt_mgr.cats_mgr
++
++ self.thread = self.scatt_mgr.thread
++
++ #TODO
++ self.mapWin.parent.toolbars["vdigit"].editingStarted.connect(self.DigitDataChanged)
++
++ #def ChangeMap(self, vectMap, layers_cats):
++ # self.vectMap = vectMap
++ # self.layers_cats = layers_cats
++
++ #ret, region, msg = RunCommand("v.to.rast",
++ # flags = "gp",
++ # getErrorMsg = True,
++ # read = True)
++
++ def _connectSignals(self):
++ self.digit.featureAdded.connect(self.AddFeature)
++ self.digit.areasDeleted.connect(self.DeleteAreas)
++ self.digit.featuresDeleted.connect(self.DeleteAreas)
++ self.digit.vertexMoved.connect(self.EditedFeature)
++ self.digit.vertexRemoved.connect(self.EditedFeature)
++ self.digit.lineEdited.connect(self.EditedFeature)
++ self.digit.featuresMoved.connect(self.EditedFeature)
++
++ def AddFeature(self, new_bboxs, new_areas_cats):
++ if not self.scatt_mgr.data_set:
++ return
++
++ self.scatt_mgr.tasks_pids['mapwin_conn'].append(self.thread.GetId())
++ self.thread.Run(callable = self.scatt_rast_updater.EditedFeature,
++ new_bboxs = new_bboxs,
++ old_bboxs = [],
++ old_areas_cats = [],
++ new_areas_cats = new_areas_cats)
++
++ def DeleteAreas(self, old_bboxs, old_areas_cats):
++ if not self.scatt_mgr.data_set:
++ return
++
++ self.scatt_mgr.tasks_pids['mapwin_conn'].append(self.thread.GetId())
++ self.thread.Run(callable = self.scatt_rast_updater.EditedFeature,
++ new_bboxs = [],
++ old_bboxs = old_bboxs,
++ old_areas_cats = old_areas_cats,
++ new_areas_cats = [])
++
++
++ def EditedFeature(self, new_bboxs, new_areas_cats, old_bboxs, old_areas_cats):
++ if not self.scatt_mgr.data_set:
++ return
++
++ self.scatt_mgr.tasks_pids['mapwin_conn'].append(self.thread.GetId())
++ self.thread.Run(callable = self.scatt_rast_updater.EditedFeature,
++ new_bboxs = new_bboxs,
++ old_bboxs = old_bboxs,
++ old_areas_cats = old_areas_cats,
++ new_areas_cats = new_areas_cats)
++
++ def DigitDataChanged(self, vectMap, digit):
++
++ self.digit = digit
++ self.vectMap = vectMap
++
++ self.scatt_rast_updater.SetVectMap(vectMap)
++
++ self._connectSignals()
++
++class IClassConnection:
++ def __init__(self, scatt_mgr, iclass_frame, cats_mgr):
++ self.iclass_frame = iclass_frame
++ self.stats_data = self.iclass_frame.stats_data
++ self.cats_mgr = cats_mgr
++ self.scatt_mgr = scatt_mgr
++
++ self.stats_data.statisticsAdded.connect(self.AddCategory)
++ self.stats_data.statisticsDeleted.connect(self.DeleteCategory)
++ self.stats_data.allStatisticsDeleted.connect(self.DeletAllCategories)
++ self.stats_data.statisticsSet.connect(self.SetCategory)
++
++ self.iclass_frame.groupSet.connect(self.GroupSet)
++
++ self.cats_mgr.setCategoryAttrs.connect(self.SetStatistics)
++ self.cats_mgr.deletedCategory.connect(self.DeleteStatistics)
++ self.cats_mgr.addedCategory.connect(self.AddStatistics)
++
++ self.iclass_frame.categoryChanged.connect(self.CategoryChanged)
++
++ self.SyncCats()
++
++ def SetData(self):
++ self.iclass_frame.AddBands()
++
++ def EmptyCategories(self):
++ self.iclass_frame.OnCategoryManager(None)
++
++ def SyncCats(self):
++ self.cats_mgr.addedCategory.disconnect(self.AddStatistics)
++ cats = self.stats_data.GetCategories()
++ for c in cats:
++ stats = self.stats_data.GetStatistics(c)
++ self.cats_mgr.AddCategory(c, stats.name, stats.color)
++ self.cats_mgr.addedCategory.connect(self.AddStatistics)
++
++ def CategoryChanged(self, cat):
++ self.cats_mgr.SetSelectedCat(cat)
++
++ def AddCategory(self, cat, name, color):
++ self.cats_mgr.addedCategory.disconnect(self.AddStatistics)
++ self.cats_mgr.AddCategory(cat_id = cat, name = name, color = color)
++ self.cats_mgr.addedCategory.connect(self.AddStatistics)
++
++ def DeleteCategory(self, cat):
++ self.cats_mgr.deletedCategory.disconnect(self.DeleteStatistics)
++ self.cats_mgr.DeleteCategory(cat)
++ self.cats_mgr.deletedCategory.connect(self.DeleteStatistics)
++
++ def DeletAllCategories(self):
++
++ self.cats_mgr.deletedCategory.disconnect(self.DeleteStatistics)
++ cats = self.stats_data.GetCategories()
++ for c in cats:
++ self.cats_mgr.DeleteCategory(c)
++ self.cats_mgr.deletedCategory.connect(self.DeleteStatistics)
++
++ def SetCategory(self, cat, stats):
++
++ self.cats_mgr.setCategoryAttrs.disconnect(self.SetStatistics)
++ cats_attr = {}
++ for attr in ['name', 'color']:
++ if stats.has_key(attr):
++ cats_attr[attr] = stats[attr]
++
++ if cats_attr:
++ self.cats_mgr.SetCategoryAttrs(cat, cats_attr)
++ self.cats_mgr.setCategoryAttrs.connect(self.SetStatistics)
++
++
++ def SetStatistics(self, cat_id, attrs_dict):
++ self.stats_data.statisticsSet.disconnect(self.SetCategory)
++ self.stats_data.GetStatistics(cat_id).SetStatistics(attrs_dict)
++ self.stats_data.statisticsSet.connect(self.SetCategory)
++
++ def AddStatistics(self, cat_id, name, color):
++ self.stats_data.statisticsAdded.disconnect(self.AddCategory)
++ self.stats_data.AddStatistics(cat_id, name, color)
++ self.stats_data.statisticsAdded.connect(self.AddCategory)
++
++ def DeleteStatistics(self, cat_id):
++ self.stats_data.statisticsDeleted.disconnect(self.DeleteCategory)
++ self.stats_data.DeleteStatistics(cat_id)
++ self.stats_data.statisticsDeleted.connect(self.DeleteCategory)
++
++ def GroupSet(self, group):
++ res = RunCommand('i.group',
++ flags = 'g',
++ group = group, subgroup = group,
++ read = True).strip()
++ if res.split('\n')[0]:
++ bands = res.split('\n')
++ self.scatt_mgr.SetData(bands)
+\ No newline at end of file
+Index: gui/wxpython/scatt_plot/sc_pl_core.py
+===================================================================
+--- gui/wxpython/scatt_plot/sc_pl_core.py (revision 0)
++++ gui/wxpython/scatt_plot/sc_pl_core.py (working copy)
+@@ -0,0 +1,619 @@
++"""!
++ at package scatt_plot.scatt_plot
++
++ at brief Non GUI functions.
++
++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
++
++#TODO
++import time
++
++import numpy as np
++
++from math import sqrt, ceil, floor
++from copy import deepcopy
++
++from grass.script import core as grass
++from core.gcmd import GException, GError, RunCommand
++
++import grass.script as grass
++
++from core_c import CreateCatRast, ComputeScatts, UpdateCatRast, \
++ SC_SCATT_DATA, SC_SCATT_CONDITIONS
++
++class Core:
++ def __init__(self):
++
++ self.an_data = AnalyzedData()
++
++ self.scatts_dt = ScattPlotsData(self.an_data)
++ self.scatt_conds_dt = ScattPlotsCondsData(self.an_data)
++
++ self.cat_rast_updater = CatRastUpdater(self.scatts_dt, self.an_data, self)
++
++ def SetData(self, bands):
++ self.an_data.Create(bands)
++
++ n_bands = len(self.GetBands())
++
++ self.scatts_dt.Create(n_bands)
++ self.scatt_conds_dt.Create(n_bands)
++
++ def AddCategory(self, cat_id):
++ self.scatts_dt.AddCategory(cat_id)
++ return self.scatt_conds_dt.AddCategory(cat_id)
++
++ def DeleteCategory(self, cat_id):
++ self.scatts_dt.DeleteCategory(cat_id)
++ self.scatt_conds_dt.DeleteCategory(cat_id)
++
++ def CleanUp(self):
++ self.scatts_dt.CleanUp()
++ self.scatt_conds_dt.CleanUp()
++
++ def GetBands(self):
++ return self.an_data.GetBands()
++
++ def GetScattsData(self):
++ return self.scatts_dt;
++
++ def GetRegion(self):
++ return self.an_data.GetRegion()
++
++ def GetCatRast(self, cat_id):
++ return self.scatts_dt.GetCatRast(cat_id)
++
++ def AddScattPlot(self, scatt_id):
++
++ self.scatts_dt.AddScattPlot(scatt_id = scatt_id)
++
++ cats_ids = self.scatts_dt.GetCategories()
++ self.ComputeCatsScatts(cats_ids)
++
++
++ def SetEditCatData(self, cat_id, scatt_id, bbox, value):
++
++ if cat_id not in self.scatts_dt.GetCategories():
++ raise GException(_("Select category for editing."))
++
++ if self.scatt_conds_dt.AddScattPlot(cat_id, scatt_id) < 0:
++ return False
++
++ arr = self.scatt_conds_dt.GetValuesArr(cat_id, scatt_id)
++
++ for k, v in bbox.iteritems():
++ bbox[k] = self._validExtend(v)
++
++ arr[bbox['btm_y'] : bbox['up_y'], bbox['btm_x'] : bbox['up_x']] = value
++ arr.flush()
++ #del arr
++
++ start_time = time.clock()
++ self.ComputeCatsScatts([cat_id])
++ print "time"
++ print time.clock() - start_time
++ return True
++
++ def ComputeCatsScatts(self, cats_ids):
++
++ requested_dt = {}
++ requested_dt_conds = {}
++
++ for c in cats_ids:
++ requested_dt_conds[c] = self.scatt_conds_dt.GetCatScatts(c)
++ requested_dt[c] = self.scatts_dt.GetCatScatts(c)
++
++ scatt_conds = self.scatt_conds_dt.GetData(requested_dt_conds)
++ scatts = self.scatts_dt.GetData(requested_dt)
++
++ bands = self.an_data.GetBands()
++
++ cats_rasts = self.scatts_dt.GetCatsRasts()
++ cats_rasts_conds = self.scatts_dt.GetCatsRastsConds()
++
++ returncode, scatts = ComputeScatts(self.an_data.GetRegion(), scatt_conds, bands,
++ len(self.GetBands()), scatts, cats_rasts_conds, cats_rasts)
++
++ #self.scatts_dt.SetData(scatts)
++
++ def CatRastUpdater(self):
++ return self.cat_rast_updater
++
++ def _validExtend(self, val):
++ #TODO do it general
++ if val > 255:
++ val = 255
++ elif val < 0:
++ val = 0
++
++ return val
++
++class CatRastUpdater:
++
++ def __init__(self, scatts_dt, an_data, core):
++ self.scatts_dt = scatts_dt
++ self.an_data = an_data # TODO may be confusing
++ self.core = core
++ self.vectMap = None
++
++ def SetVectMap(self, vectMap):
++ self.vectMap = vectMap
++
++ def EditedFeature(self, new_bboxs, new_areas_cats, old_bboxs, old_areas_cats):
++ #TODO possible optimization - bbox only of vertex and its two neighbours
++
++ bboxs = old_bboxs + new_bboxs
++ areas_cats = old_areas_cats + new_areas_cats
++
++ updated_cats = []
++
++ for i in range(len(areas_cats)):
++ self._updateCatRast(bboxs[i], areas_cats[i], updated_cats)
++
++ return updated_cats
++
++ def _updateCatRast(self, bbox, areas_cats, updated_cats):
++
++ rasterized_cats = []
++ for c in range(len(areas_cats)):
++
++ if not areas_cats[c]:
++ continue
++
++ layer = areas_cats[c].keys()[0]
++ cat = areas_cats[c][layer][0]
++
++ if cat in rasterized_cats:
++ continue
++
++ rasterized_cats.append(cat)
++ updated_cats.append(cat)
++
++ grass_region = self._create_grass_region_env(bbox)
++
++ #TODO hack
++ patch_rast = "temp_scatt_patch"
++ self._rasterize(grass_region, layer, cat, patch_rast)
++
++ region = self.an_data.GetRegion()
++ UpdateCatRast(patch_rast, region, self.scatts_dt.GetCatRastCond(cat))
++
++ RunCommand("g.remove",
++ rast = patch_rast)#,
++
++ def _rasterize(self, grass_region, layer, cat, out_rast):
++
++ #TODO different thread may be problem when user edits map
++ ret, text, msg = RunCommand("v.build",
++ map = self.vectMap,
++ getErrorMsg = True,
++ read = True)#,
++
++ #TODO thread problem with env variable remove it!!!!
++ environs = os.environ.copy()
++ environs["GRASS_REGION"] = grass_region["GRASS_REGION"]
++
++ ret, text, msg = RunCommand("v.to.rast",
++ input = self.vectMap,
++ use = "cat",
++ layer = str(layer),
++ cat = str(cat),
++ output = out_rast,
++ getErrorMsg = True,
++ read = True,
++ overwrite = True,
++ env = environs)
++ def _create_grass_region_env(self, bbox):
++
++ region = self.an_data.GetRegion()
++ new_region = {}
++
++ if bbox["maxy"] <= region["s"]:
++ return 0
++ elif bbox["maxy"] >= region["n"]:
++ new_region["n"] = bbox["maxy"]
++ else:
++ new_region["n"] = ceil((bbox["maxy"] - region["s"]) / region["nsres"]) * region["nsres"] + region["s"]
++
++ if bbox["miny"] >= region["n"]:
++ return 0
++ elif bbox["miny"] <= region["s"]:
++ new_region["s"] = bbox["miny"]
++ else:
++ new_region["s"] = floor((bbox["miny"] - region["s"]) / region["nsres"]) * region["nsres"] + region["s"]
++
++ if bbox["maxx"] <= region["w"]:
++ return 0
++ elif bbox["maxx"] >= region["e"]:
++ new_region["e"] = bbox["maxx"]
++ else:
++ new_region["e"] = ceil((bbox["maxx"] - region["w"]) / region["ewres"]) * region["ewres"] + region["w"]
++
++ if bbox["minx"] >= region["e"]:
++ return 0
++ elif bbox["minx"] <= region["w"]:
++ new_region["w"] = bbox["minx"]
++ else:
++ new_region["w"] = floor((bbox["minx"] - region["w"]) / region["ewres"]) * region["ewres"] + region["w"]
++
++ #TODO check regions resolutin
++ new_region["nsres"] = region["nsres"]
++ new_region["ewres"] = region["ewres"]
++
++ return {"GRASS_REGION" : grass.region_env(**new_region)}
++
++class AnalyzedData:
++
++ def __init__(self):
++
++ self.bands = []
++ self.bands_info = {}
++
++ self.region = None
++
++ def GetRegion(self):
++ return self.region
++
++ def Create(self, bands):
++
++ self.bands = bands
++ self.region = None
++
++ ret, region, msg = RunCommand("g.region",
++ flags = "gp",
++ getErrorMsg = True,
++ read = True)
++
++ if ret != 0:
++ raise GException("g.region failed:\n%s" % msg)
++
++
++ self.bands_info = {}
++ for b in bands:
++ self.bands_info[b] = self._getRasterInfo(b)
++ if self.bands_info[b]["datatype"] != "CELL":
++ raise GException(_("Raster <%s> is not <CELL> type.") % (b))
++ #TODO size of raster check
++
++ self.region = self._parseRegion(region)
++
++ def _getRasterInfo(self, rast):
++ """
++ """
++ ret, out, msg = RunCommand("r.info",
++ map = rast,
++ flags = "rg",
++ getErrorMsg = True,
++ read = True)
++
++ if ret != 0:
++ raise GException("r.info failed:\n%s" % msg)
++
++ out = out.split("\n")
++ raster_info = {}
++
++ for b in out:
++ if not b.strip():
++ continue
++ k, v = b.split("=")
++ if k == "datatype":
++ pass
++ elif k in ['rows', 'cols', 'cells', 'min', 'max']:
++ v = int(v)
++ else:
++ v = float(v)
++
++ raster_info[k] = v
++
++ return raster_info
++
++ def GetBands(self):
++ return self.bands
++
++ def GetBandInfo(self, band_id):
++ band = self.bands[band_id]
++ return self.bands_info[band]
++
++ def _parseRegion(self, region_str):
++
++ region = {}
++ region_str = region_str.splitlines()
++
++ for param in region_str:
++ k, v = param.split("=")
++ if k in ["rows", "cols", "cells"]:
++ v = int(v)
++ else:
++ v = float(v)
++ region[k] = v
++
++ return region
++
++class ScattPlotsCondsData:
++
++ def __init__(self, an_data):
++
++ self.an_data = an_data
++
++ #TODO
++ self.max_n_cats = 10
++
++ self.dtype = 'uint8'
++ self.type = 1;
++ self.CleanUp()
++
++ def CleanUp(self):
++
++ self.cats = {}
++
++ self.n_scatts = -1
++ self.n_bands = -1
++
++ for cat_id in self.cats.keys():
++ self.DeleteCategory(cat_id)
++
++ def Create(self, n_bands):
++
++ self.CleanUp()
++
++ self.n_scatts = (n_bands - 1) * n_bands / 2;
++ self.n_bands = n_bands
++
++ self.AddCategory(cat_id = 0)
++
++ def AddCategory(self, cat_id):
++
++ if cat_id not in self.cats.keys():
++ self.cats[cat_id] = {}
++ return cat_id
++ return -1
++
++ def DeleteCategory(self, cat_id):
++
++ if cat_id not in self.cats.keys():
++ return False
++
++ for scatt in self.cats[cat_id].itervalues():
++ del scatt['np_vals']
++
++ del self.cats[cat_id]
++
++ return True
++
++ def GetCategories(self):
++ return self.cats.keys()
++
++ def GetCatScatts(self, cat_id):
++
++ if not self.cats.has_key(cat_id):
++ return False
++
++ return self.cats[cat_id].keys()
++
++
++ def AddScattPlot(self, cat_id, scatt_id):
++
++ if not self.cats.has_key(cat_id):
++ return -1
++
++ if self.cats[cat_id].has_key(scatt_id):
++ return 0
++
++ b_i = self.GetBandsInfo(scatt_id)
++
++ shape = (b_i['b2']['max'] - b_i['b2']['min'] + 1, b_i['b1']['max'] - b_i['b1']['min'] + 1)
++
++ np_vals = np.memmap(grass.tempfile(), dtype=self.dtype, mode='w+', shape = shape)
++ np_vals.flush()
++
++ self.cats[cat_id][scatt_id] = {
++ 'np_vals' : np_vals
++ }
++
++ return 1
++
++ def GetBandsInfo(self, scatt_id):
++ b1, b2 = idScattToidBands(scatt_id, len(self.an_data.GetBands()))
++
++ b1_info = self.an_data.GetBandInfo(b1)
++ b2_info = self.an_data.GetBandInfo(b2)
++
++ bands_info = {'b1' : b1_info,
++ 'b2' : b2_info}
++
++ return bands_info
++
++ def DeleScattPlot(self, cat_id, scatt_id):
++
++ if not self.cats.has_key(cat_id):
++ return False
++
++ if not self.cats[cat_id].has_key(scatt_id):
++ return False
++
++ del self.cats[cat_id][scatt_id]
++ return True
++
++ def GetValuesArr(self, cat_id, scatt_id):
++
++ if not self.cats.has_key(cat_id):
++ return None
++
++ if not self.cats[cat_id].has_key(scatt_id):
++ return None
++
++ return self.cats[cat_id][scatt_id]['np_vals']
++
++ def GetData(self, requested_dt):
++
++ cats = {}
++ for cat_id, scatt_ids in requested_dt.iteritems():
++ if not cats.has_key(cat_id):
++ cats[cat_id] = {}
++ for scatt_id in scatt_ids:
++ # if key is missing condition is always True (full scatter plor is computed)
++ if self.cats[cat_id].has_key(scatt_id):
++ cats[cat_id][scatt_id] = {'np_vals' : self.cats[cat_id][scatt_id]['np_vals'],
++ 'bands_info' : self.GetBandsInfo(scatt_id)}
++
++ return cats
++
++ def SetData(self, cats):
++
++ for cat_id, scatt_ids in cats.iteritems():
++ for scatt_id in scatt_ids:
++ # if key is missing condition is always True (full scatter plor is computed)
++ if self.cats[cat_id].has_key(scatt_id):
++ self.cats[cat_id][scatt_id]['np_vals'] = cats[cat_id][scatt_id]['np_vals']
++
++class ScattPlotsData(ScattPlotsCondsData):
++
++ def __init__(self, an_data):
++
++ self.cats_rasts = {}
++ self.cats_rasts_conds = {}
++ self.scatts_ids = []
++
++ ScattPlotsCondsData.__init__(self, an_data)
++
++ self.dtype = 'uint32'
++
++ #TODO
++ self.type = 0
++
++ def AddCategory(self, cat_id):
++ cat_id = ScattPlotsCondsData.AddCategory(self, cat_id)
++ if cat_id < 0:
++ return cat_id
++
++ for scatt_id in self.scatts_ids:
++ ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
++
++ if cat_id == 0:
++ self.cats_rasts_conds[cat_id] = None
++ self.cats_rasts[cat_id] = None
++ 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])
++
++ return cat_id
++
++ def DeleteCategory(self, cat_id):
++
++ ScattPlotsCondsData.DeleteCategory(self, cat_id)
++
++ grass.try_remove(self.cats_rasts_conds[cat_id])
++ del self.cats_rasts_conds[cat_id]
++
++ grass.try_remove(self.cats_rasts[cat_id])
++ del self.cats_rasts[cat_id]
++
++ return True
++
++ def AddScattPlot(self, scatt_id):
++
++ if scatt_id in self.scatts_ids:
++ return False
++
++ self.scatts_ids.append(scatt_id)
++ for cat_id in self.cats.iterkeys():
++ ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
++
++ return True
++
++ def DeleteScatterPlot(self, scatt_id):
++
++ if scatt_id not in self.scatts_ids:
++ return False
++
++ self.scatts_ids.remove(scatt_id)
++
++ for cat_id in self.cats.iterkeys():
++ ScattPlotsCondsData.DeleteScattPlot(self, cat_id, scatt_id)
++
++ return True
++
++ def GetScatt(self, scatt_id):
++ if scatt_id not in self.scatts_ids:
++ return False
++
++ scatts = {}
++ for cat_id in self.cats.iterkeys():
++ scatts[cat_id] = {'np_vals' : self.cats[cat_id][scatt_id]['np_vals'],
++ 'bands_info' : self.GetBandsInfo(scatt_id)}
++ return scatts
++
++ def CleanUp(self):
++
++ ScattPlotsCondsData.CleanUp(self)
++ for tmp in self.cats_rasts_conds:
++ grass.try_remove(tmp)
++ for tmp in self.cats_rasts:
++ grass.try_remove(tmp)
++
++ self.cats_rasts = {}
++ self.cats_rasts_conds = {}
++
++
++ def GetCatRast(self, cat_id):
++ return self.cats_rasts[cat_id]
++
++ def GetCatRastCond(self, cat_id):
++ return self.cats_rasts_conds[cat_id]
++
++ def GetCatsRastsConds(self):
++ max_cat_id = max(self.cats_rasts_conds.keys())
++
++ cats_rasts_conds = [''] * (max_cat_id + 1)
++ for i_cat_id, i_rast in self.cats_rasts_conds.iteritems():
++ cats_rasts_conds[i_cat_id] = i_rast
++
++ return cats_rasts_conds
++
++ def GetCatsRasts(self):
++ max_cat_id = max(self.cats_rasts.keys())
++
++ cats_rasts = [''] * (max_cat_id + 1)
++ for i_cat_id, i_rast in self.cats_rasts.iteritems():
++ cats_rasts[i_cat_id] = i_rast
++
++ return cats_rasts
++
++#TODO move to utils?
++def idScattToidBands(scatt_id, n_bands):
++
++ n_b1 = n_bands - 1
++
++ band_1 = (int) ((2 * n_b1 + 1 - sqrt(((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
++
++ return band_1, band_2
++
++
++def idBandsToidScatt(band_1_id, band_2_id, n_bands):
++
++ if band_2_id < band_1_id:
++ tmp = band_1
++ band_1_id = band_2_id
++ band_2_id = tmp
++
++ n_b1 = n_bands - 1
++
++ scatt_id = (band_1_id * (2 * n_b1 + 1) - band_1_id * band_1_id) / 2 + band_2_id - band_1_id - 1
++
++ return scatt_id
++
+Index: gui/wxpython/Makefile
+===================================================================
+--- 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/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")
++
+ # 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)
+
++ self.editingStarted.emit(vectMap = mapLayer.GetName(), digit = self.digit)
+ return True
+
+ def StopEditing(self):
Index: gui/wxpython/vdigit/wxdigit.py
===================================================================
---- gui/wxpython/vdigit/wxdigit.py (revision 57336)
+--- gui/wxpython/vdigit/wxdigit.py (revision 57437)
+++ gui/wxpython/vdigit/wxdigit.py (working copy)
@@ -17,7 +17,7 @@
(and NumPy would be an excellent candidate for acceleration via
@@ -2756,12 +3129,14 @@
from core.gcmd import GError
from core.debug import Debug
from core.settings import UserSettings
-@@ -176,7 +178,17 @@
+@@ -176,7 +178,19 @@
if self.poMapInfo:
self.InitCats()
-
+
++ self.use_signals = False
++
+ #TODO signal for errors?
+ self.featureAdded = Signal('IVDigit.featureAdded')
+ self.areasDeleted = Signal('IVDigit.areasDeleted')
@@ -2775,7 +3150,7 @@
def __del__(self):
Debug.msg(1, "IVDigit.__del__()")
Vect_destroy_line_struct(self.poPoints)
-@@ -394,7 +406,6 @@
+@@ -394,7 +408,6 @@
@return tuple (number of added features, feature ids)
"""
@@ -2783,7 +3158,7 @@
layer = self._getNewFeaturesLayer()
cat = self._getNewFeaturesCat()
-@@ -419,10 +430,14 @@
+@@ -419,10 +432,14 @@
return (-1, None)
self.toolbar.EnableUndo()
@@ -2795,19 +3170,19 @@
+ ret = self._addFeature(vtype, points, layer, cat,
+ self._getSnapMode(), self._display.GetThreshold())
+ if ret[0] > -1:
-+ self.featureAdded.emit(new_geom = points, cat = {layer : [cat]})
++ self.featureAdded.emit(new_bboxs = [self._createBbox(points)], new_areas_cats = [[{layer : [cat]}, None]])
+
+ return ret
+
def DeleteSelectedLines(self):
"""!Delete selected features
-@@ -434,16 +449,25 @@
+@@ -434,16 +451,27 @@
# colect categories for delete if requested
deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
catDict = dict()
+
-+ old_geoms = []
++ old_bboxs = []
+ old_areas_cats = []
if deleteRec:
for i in self._display.selected['ids']:
@@ -2815,8 +3190,10 @@
if Vect_read_line(self.poMapInfo, None, self.poCats, i) < 0:
self._error.ReadLine(i)
-+ old_geoms.append(self._getGeom(i))
-+ old_areas_cats.append(self._getLineAreasCategories(i))
++ ret = self._getLineAreaBboxCats(i)
++ if ret:
++ old_bboxs += ret[0]
++ old_areas_cats += ret[1]
+
cats = self.poCats.contents
- for j in range(cats.n_cats):
@@ -2832,17 +3209,17 @@
poList = self._display.GetSelectedIList()
nlines = Vedit_delete_lines(self.poMapInfo, poList)
-@@ -456,7 +480,8 @@
+@@ -456,7 +484,8 @@
self._deleteRecords(cats)
self._addChangeset()
self.toolbar.EnableUndo()
-
-+ self.featuresDeleted.emit(old_geoms = old_geoms, old_areas_cats = old_areas_cats)
++ self.featuresDeleted.emit(old_bboxs = old_bboxs, old_areas_cats = old_areas_cats)
+
return nlines
def _deleteRecords(self, cats):
-@@ -512,22 +537,123 @@
+@@ -512,22 +541,171 @@
@return number of deleted
"""
@@ -2853,7 +3230,7 @@
cList = poList.contents
nareas = 0
-+ old_geoms = []
++ old_bboxs = []
+ old_areas_cats = []
+
for i in range(cList.n_values):
@@ -2864,8 +3241,8 @@
+
+ area = Vect_get_centroid_area(self.poMapInfo, cList.value[i]);
+ if area > 0:
-+ geoms, cats = self._getaAreaGeomsCats(area)
-+ old_geoms += geoms
++ bbox, cats = self._getaAreaBboxCats(area)
++ old_bboxs += bbox
+ old_areas_cats += cats
+
nareas += Vedit_delete_area_centroid(self.poMapInfo, cList.value[i])
@@ -2873,13 +3250,32 @@
if nareas > 0:
self._addChangeset()
self.toolbar.EnableUndo()
-+ self.areasDeleted.emit(old_geoms = old_geoms, old_areas_cats = old_areas_cats)
++ self.areasDeleted.emit(old_bboxs = old_bboxs, old_areas_cats = old_areas_cats)
+
+ return nareas
+
++ def _getLineAreaBboxCats(self, ln_id):
++ ltype = Vect_read_line(self.poMapInfo, None, None, ln_id)
+
-+ def _getaAreaGeomsCats(self, area):
++ if ltype == GV_CENTROID:
++ #TODO centroid opttimization, can be adited also its area -> it will appear two times in new_ lists
++ return self._getCentroidAreaBboxCats(ln_id)
++ else:
++ return [self._getBbox(ln_id)], [self._getLineAreasCategories(ln_id)]
+
++
++ def _getCentroidAreaBboxCats(self, centroid):
++ if not Vect_line_alive(self.poMapInfo, centroid):
++ return None
++
++ area = Vect_get_centroid_area(self.poMapInfo, centroid)
++ if area > 0:
++ return self._getaAreaBboxCats(area)
++ else:
++ return None
++
++ def _getaAreaBboxCats(self, area):
++
+ po_b_list = Vect_new_list()
+ Vect_get_area_boundaries(self.poMapInfo, area, po_b_list);
+ b_list = po_b_list.contents
@@ -2888,11 +3284,11 @@
+ areas_cats = []
+
+ if b_list.n_values > 0:
-+ for i_line in range(b_list.n_values):
++ for i_line in range(b_list.n_values):
+
+ line = b_list.value[i_line];
+
-+ geoms.append(self._getGeom(abs(line)))
++ geoms.append(self._getBbox(abs(line)))
+ areas_cats.append(self._getLineAreasCategories(abs(line)))
- return nareas
@@ -2901,6 +3297,8 @@
+ return geoms, areas_cats
+
+ def _getLineAreasCategories(self, ln_id):
++ if not Vect_line_alive (self.poMapInfo, ln_id):
++ return []
+
+ ltype = Vect_read_line(self.poMapInfo, None, None, ln_id)
+ if ltype != GV_BOUNDARY:
@@ -2926,7 +3324,9 @@
+ return cats
+
+ def _getCategories(self, ln_id):
-+
++ if not Vect_line_alive (self.poMapInfo, ln_id):
++ return none
++
+ poCats = Vect_new_cats_struct()
+ if Vect_read_line(self.poMapInfo, None, poCats, ln_id) < 0:
+ Vect_destroy_cats_struct(poCats)
@@ -2944,17 +3344,42 @@
+ Vect_destroy_cats_struct(poCats)
+ return cats
+
-+ def _getGeom(self, ln_id):
++ def _getBbox(self, ln_id):
++ if not Vect_line_alive (self.poMapInfo, ln_id):
++ return None
+
+ poPoints = Vect_new_line_struct()
+ if Vect_read_line(self.poMapInfo, poPoints, None, ln_id) < 0:
+ Vect_destroy_line_struct(poPoints)
-+ return None
++ return []
+
+ geom = self._convertGeom(poPoints)
++ bbox = self._createBbox(geom)
+ Vect_destroy_line_struct(poPoints)
-+ return geom
++ return bbox
+
++ def _createBbox(self, points):
++
++ bbox = {}
++ for pt in points:
++ if not bbox.has_key('maxy'):
++ bbox['maxy'] = pt[1]
++ bbox['miny'] = pt[1]
++ bbox['maxx'] = pt[0]
++ bbox['minx'] = pt[0]
++ continue
++
++ if bbox['maxy'] < pt[1]:
++ bbox['maxy'] = pt[1]
++ elif bbox['miny'] > pt[1]:
++ bbox['miny'] = pt[1]
++
++ if bbox['maxx'] < pt[0]:
++ bbox['maxx'] = pt[0]
++ elif bbox['minx'] > pt[0]:
++ bbox['minx'] = pt[0]
++ return bbox
++
+ def _convertGeom(self, poPoints):
+
+ Points = poPoints.contents
@@ -2968,7 +3393,7 @@
def MoveSelectedLines(self, move):
"""!Move selected features
-@@ -536,16 +662,39 @@
+@@ -536,16 +714,43 @@
if not self._checkMap():
return -1
@@ -2981,48 +3406,53 @@
poList = self._display.GetSelectedIList()
+
-+ old_geoms = []
++ old_bboxs = []
+ old_areas_cats = []
+ for sel_id in self._display.selected['ids']:
-+ old_geoms.append(self._getGeom(sel_id))
-+ old_areas_cats.append(self._getLineAreasCategories(sel_id))
-+
-+ poNewIds = Vect_new_list()
++ ret = self._getLineAreaBboxCats(sel_id)
++ if ret:
++ old_bboxs += ret[0]
++ old_areas_cats += ret[1]
++
++ Vect_set_updated(self.poMapInfo, 1)
++ n_up_lines_old = Vect_get_num_updated_lines(self.poMapInfo)
nlines = Vedit_move_lines(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
poList,
move[0], move[1], 0,
-- snap, thresh)
-+ snap, thresh, poNewIds)
+ snap, thresh)
+
Vect_destroy_list(poList)
-
-+ cList = poNewIds.contents
+-
+
+ if nlines > 0:
++ new_bboxs = []
+ new_areas_cats = []
-+ for i in range(cList.n_values):
-+ new_id = cList.value[i]
-+ new_areas_cats.append(self._getLineAreasCategories(new_id))
++ n_up_lines = Vect_get_num_updated_lines(self.poMapInfo)
++ for i in range(n_up_lines_old, n_up_lines):
++ new_id = Vect_get_updated_line(self.poMapInfo, i)
++ ret = self._getLineAreaBboxCats(new_id)
++ if ret:
++ new_bboxs += ret[0]
++ new_areas_cats += ret[1]
+
-+ Vect_destroy_list(poNewIds)
-+
if nlines > 0 and self._settings['breakLines']:
for i in range(1, nlines):
self._breakLineAtIntersection(nlines + i, None, changeset)
-@@ -553,7 +702,11 @@
+@@ -553,7 +758,12 @@
if nlines > 0:
self._addChangeset()
self.toolbar.EnableUndo()
-
-+
-+ self.featuresMoved.emit(move = move,
-+ old_geoms = old_geoms,
++
++ self.featuresMoved.emit(new_bboxs = new_bboxs,
++ old_bboxs = old_bboxs,
+ old_areas_cats = old_areas_cats,
+ new_areas_cats = new_areas_cats)
++
return nlines
def MoveSelectedVertex(self, point, move):
-@@ -571,20 +724,33 @@
+@@ -571,12 +781,19 @@
if len(self._display.selected['ids']) != 1:
return -1
@@ -3032,8 +3462,8 @@
+ poList = self._display.GetSelectedIList()
+
+ cList = poList.contents
-+ old_geom = self._getGeom(cList.value[0])
-+ old_areas_cats = self._getLineAreasCategories(cList.value[0])
++ old_bboxs = [self._getBbox(cList.value[0])]
++ old_areas_cats = [self._getLineAreasCategories(cList.value[0])]
+
Vect_reset_line(self.poPoints)
Vect_append_point(self.poPoints, point[0], point[1], 0.0)
@@ -3041,101 +3471,112 @@
- # move only first found vertex in bbox
- poList = self._display.GetSelectedIList()
+
-+ poNewIds = Vect_new_list()
++ Vect_set_updated(self.poMapInfo, 1)
++ n_up_lines_old = Vect_get_num_updated_lines(self.poMapInfo)
moved = Vedit_move_vertex(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
poList, self.poPoints,
self._display.GetThreshold(type = 'selectThresh'),
- self._display.GetThreshold(),
+@@ -584,7 +801,17 @@
move[0], move[1], 0.0,
-- 1, self._getSnapMode())
-+ 1, self._getSnapMode(), poNewIds)
+ 1, self._getSnapMode())
Vect_destroy_list(poList)
-
+
-+ new_id = poNewIds.contents.value[0]
-+ Vect_destroy_list(poNewIds)
++ n_up_lines = Vect_get_num_updated_lines(self.poMapInfo)
+
-+ if new_id > -1:
-+ new_geom = self._getGeom(new_id)
-+ new_areas_cats = self._getLineAreasCategories(new_id)
++ if moved > 0:
++ new_bboxs = []
++ new_areas_cats = []
++ for i in range(n_up_lines_old, n_up_lines):
++ new_id = Vect_get_updated_line(self.poMapInfo, i)
++ new_bboxs.append(self._getBbox(new_id))
++ new_areas_cats.append(self._getLineAreasCategories(new_id))
+
if moved > 0 and self._settings['breakLines']:
self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
None)
-@@ -592,7 +758,13 @@
+@@ -592,7 +819,12 @@
if moved > 0:
self._addChangeset()
self.toolbar.EnableUndo()
-
+
-+ if new_id > -1:
-+ self.vertexMoved.emit(new_geom = new_geom,
++ self.vertexMoved.emit(new_bboxs = new_bboxs,
+ new_areas_cats = new_areas_cats,
+ old_areas_cats = old_areas_cats,
-+ old_geom = old_geom)
++ old_bboxs = old_bboxs)
+
return moved
def AddVertex(self, coords):
-@@ -681,6 +853,9 @@
+@@ -681,6 +913,9 @@
self._error.ReadLine(line)
return -1
-+ old_geom = self._getGeom(line)
-+ old_areas_cats = self._getLineAreasCategories(line)
++ old_bboxs = [self._getBbox(line)]
++ old_areas_cats = [self._getLineAreasCategories(line)]
+
# build feature geometry
Vect_reset_line(self.poPoints)
for p in coords:
-@@ -703,7 +878,15 @@
+@@ -696,6 +931,9 @@
+
+ newline = Vect_rewrite_line(self.poMapInfo, line, ltype,
+ self.poPoints, self.poCats)
++ if newline > 0:
++ new_geom = [self._getBbox(newline)]
++ new_areas_cats = [self._getLineAreasCategories(newline)]
+
+ if newline > 0 and self._settings['breakLines']:
+ self._breakLineAtIntersection(newline, None)
+@@ -703,7 +941,12 @@
if newline > 0:
self._addChangeset()
self.toolbar.EnableUndo()
-
-+
-+ new_geom = self._getGeom(newline)
-+ new_areas_cats = self._getLineAreasCategories(newline)
+
-+ self.lineEdited.emit(old_geom = old_geom,
++ self.lineEdited.emit(old_bboxs = old_bboxs,
+ old_areas_cats = old_areas_cats,
-+ new_geom = new_geom,
++ new_bboxs = new_bboxs,
+ new_areas_cats = new_areas_cats)
+
return newline
def FlipLine(self):
-@@ -1510,26 +1693,49 @@
+@@ -1510,26 +1753,52 @@
return 0
poList = self._display.GetSelectedIList()
+ cList = poList.contents
+
-+ old_geom = self._getGeom(cList.value[0])
-+ old_areas_cats = self._getLineAreasCategories(cList.value[0])
++ old_bboxs = [self._getBbox(cList.value[0])]
++ old_areas_cats = [self._getLineAreasCategories(cList.value[0])]
+
Vect_reset_line(self.poPoints)
Vect_append_point(self.poPoints, coords[0], coords[1], 0.0)
thresh = self._display.GetThreshold(type = 'selectThresh')
-+ poNewIds = Vect_new_list()
-+
++ Vect_set_updated(self.poMapInfo, 1)
++ n_up_lines_old = Vect_get_num_updated_lines(self.poMapInfo)
if add:
ret = Vedit_add_vertex(self.poMapInfo, poList,
-- self.poPoints, thresh)
-+ self.poPoints, thresh, poNewIds)
+ self.poPoints, thresh)
else:
ret = Vedit_remove_vertex(self.poMapInfo, poList,
-- self.poPoints, thresh)
-+ self.poPoints, thresh, poNewIds)
+ self.poPoints, thresh)
+
-+ new_id = poNewIds.contents.value[0]
-+ Vect_destroy_list(poNewIds)
Vect_destroy_list(poList)
+
-+ if new_id > -1:
-+ new_geom = self._getGeom(new_id)
-+ new_areas_cats = self._getLineAreasCategories(new_id)
++ if ret > 0:
++ new_bboxs = []
++ new_areas_cats = []
++
++ n_up_lines = Vect_get_num_updated_lines(self.poMapInfo)
++ for i in range(n_up_lines_old, n_up_lines):
++ new_id = Vect_get_updated_line(self.poMapInfo, i)
++ new_areas_cats.append(self._getLineAreasCategories(new_id))
++ new_bboxs.append(self._getBbox(new_id))
if not add and ret > 0 and self._settings['breakLines']:
self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
@@ -3146,74 +3587,494 @@
self._addChangeset()
-
+
-+ if new_id > -1:
+ if add:
-+ self.vertexAdded.emit(old_geom = old_geom, new_geom = new_geom)
++ self.vertexAdded.emit(old_bboxs = old_bboxs, new_bboxs = new_bboxs)
+ else:
-+ self.vertexRemoved.emit(old_geom = old_geom,
-+ new_geom = new_geom,
++ self.vertexRemoved.emit(old_bboxs = old_bboxs,
++ new_bboxs = new_bboxs,
+ old_areas_cats = old_areas_cats,
+ new_areas_cats = new_areas_cats)
+
return 1
def GetLineCats(self, line):
-Index: gui/wxpython/vdigit/toolbars.py
+Index: gui/wxpython/mapdisp/toolbars.py
===================================================================
---- gui/wxpython/vdigit/toolbars.py (revision 57336)
-+++ gui/wxpython/vdigit/toolbars.py (working copy)
-@@ -17,6 +17,7 @@
- import wx
+--- 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)))
+
+ def OnDecoration(self, event):
+ """!Decorations overlay menu
+Index: gui/wxpython/mapdisp/frame.py
+===================================================================
+--- gui/wxpython/mapdisp/frame.py (revision 57437)
++++ gui/wxpython/mapdisp/frame.py (working copy)
+@@ -226,6 +226,7 @@
+ #
+ 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']
- 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")
++ def OnScatterplot2(self, event):
++ """!Init interactive scatterplot tools
++ """
++ if self.dialogs['scatt_plot']:
++ self.dialogs['scatt_plot'].Raise()
++ return
+
- # 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)
-@@ -820,6 +823,7 @@
- alpha = int(opacity * 255)
- self.digit.GetDisplay().UpdateSettings(alpha = alpha)
-
-+ self.editingStarted.emit(vectMap = mapLayer.GetName())
- return True
-
- def StopEditing(self):
-Index: gui/wxpython/Makefile
++ 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: lib/imagery/scatt_sccats.c
===================================================================
---- gui/wxpython/Makefile (revision 57336)
-+++ 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 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 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)
-
+--- lib/imagery/scatt_sccats.c (revision 0)
++++ lib/imagery/scatt_sccats.c (working copy)
+@@ -0,0 +1,421 @@
++/*!
++ \file lib/imagery/scatt_cat_rast.c
++
++ \brief Imagery library - functions for manipulation with scatter plot structs.
++
++ Copyright (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.
++
++ \author Stepan Turek <stepan.turek at seznam.cz> (Mentor: Martin Landa)
++ */
++
++#include <grass/raster.h>
++#include <grass/imagery.h>
++#include <grass/gis.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <math.h>
++#include <string.h>
++
++/*!
++ \brief Compute band ids from scatter plot id.
++
++ \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
++ */
++static void id_scatt_to_bands(const int scatt_id, const int n_bands, int * band_1, int * band_2)
++{
++ 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);
++
++ * band_2 = scatt_id - ((* band_1) * (2 * n_b1 + 1) - (* band_1) * (* band_1)) / 2 + (* band_1) + 1;
++
++ return;
++}
++
++
++/*!
++ \brief Compute scatter plot id from band ids.
++
++ \param n_bands number of bands
++ \param band_1 id of band1
++ \param band_2 id of band2
++ \param [out] scatt_id scatter plot id
++ */
++static void bands_to_id_scatt(const int band_1, const int band_2, 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;
++
++ return;
++}
++
++/*!
++ \brief Initialize structury for soring scatter plots data.
++
++ \param cats pointer to scCats struct
++ \param n_bands number of bands
++ \param type SC_SCATT_DATA - stores scatter plots
++ \param type SC_SCATT_CONDITIONS - stores selected areas in scatter plots
++ */
++void I_sc_init_cats(struct scCats * cats, int n_bands, int type)
++{
++ int i_cat;
++
++ cats->type = type;
++
++ cats->n_cats = 100;
++ cats->n_a_cats = 0;
++
++ cats->n_bands = n_bands;
++ cats->n_scatts = (n_bands - 1) * n_bands / 2;
++
++ cats->cats_arr = (struct scScatts **) G_malloc(cats->n_cats * sizeof(struct scScatts *));
++ memset(cats->cats_arr, 0, cats-> n_cats * sizeof(struct scScatts *));
++
++ cats->cats_ids = (int *) G_malloc(cats->n_cats * sizeof(int));
++ cats->cats_idxs =(int *) G_malloc(cats->n_cats * sizeof(int));
++
++ for(i_cat = 0; i_cat < cats->n_cats; i_cat++)
++ cats->cats_idxs[i_cat] = -1;
++
++ return;
++}
++
++/*!
++ \brief Free date of struct scCats, the structure itself remains alocated. .
++
++ \param cats pointer to existing scCats struct
++ */
++void I_sc_free_cats(struct scCats * cats)
++{
++ int i_cat;
++
++ for(i_cat = 0; i_cat < cats->n_a_cats; i_cat++)
++ {
++ if(cats->cats_arr[i_cat])
++ {
++ G_free(cats->cats_arr[i_cat]->scatt_idxs);
++ G_free(cats->cats_arr[i_cat]->scatts_bands);
++ G_free(cats->cats_arr[i_cat]->scatts_arr);
++ G_free(cats->cats_arr[i_cat]);
++ }
++ }
++
++ G_free(cats->cats_ids);
++ G_free(cats->cats_idxs);
++ G_free(cats->cats_arr);
++
++ cats->n_cats = 0;
++ cats->n_a_cats = 0;
++ cats->n_bands = 0;
++ cats->n_scatts = 0;
++ cats->type = -1;
++
++ return;
++}
++
++#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
++ */
++int I_sc_add_cat(struct scCats * cats, int cat_id)
++{
++ int i_scatt;
++ int n_a_cats = cats->n_a_cats;
++
++ if(cat_id < 0 || cat_id > cats->n_cats)
++ return -1;
++
++ if(cat_id >= cats->n_cats)
++ return -2;
++
++ 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;
++
++ cats->cats_arr[n_a_cats] = (struct scScatts *) G_malloc(sizeof(struct scScatts));
++
++ cats->cats_arr[n_a_cats]->scatts_arr = (struct scdScattData **) G_malloc(cats->n_scatts * sizeof(struct scdScattData *));
++ memset((cats->cats_arr[n_a_cats]->scatts_arr), 0, cats->n_scatts * sizeof(struct scdScattData *));
++
++ cats->cats_arr[n_a_cats]->n_a_scatts = 0;
++
++ cats->cats_arr[n_a_cats]->scatts_bands = (int *) G_malloc(cats->n_scatts * 2 * sizeof(int));
++
++ cats->cats_arr[n_a_cats]->scatt_idxs = (int *) G_malloc(cats->n_scatts * sizeof(int));
++ for(i_scatt = 0; i_scatt < cats->n_scatts; i_scatt++)
++ cats->cats_arr[n_a_cats]->scatt_idxs[i_scatt] = -1;
++
++ ++cats->n_a_cats;
++
++ return 0;
++}
++
++#if 0
++int I_sc_delete_cat(struct scCats * cats, int cat_id)
++{
++ int cat_idx, i_cat;
++
++ if(cat_id < 0 || cat_id >= cats->n_cats)
++ return -1;
++
++ cat_idx = cats->cats_idxs[cat_id];
++ if(cat_idx < 0)
++ return -1;
++
++ G_free(cats->cats_arr[cat_idx]->scatt_idxs);
++ G_free(cats->cats_arr[cat_idx]->scatts_bands);
++ G_free(cats->cats_arr[cat_idx]->scatts_arr);
++ G_free(cats->cats_arr[cat_idx]);
++
++ for(i_cat = cat_idx; i_cat < cats->n_a_cats - 1; i_cat++)
++ {
++ cats->cats_arr[i_cat] = cats->cats_arr[i_cat + 1];
++ cats->cats_ids[i_cat] = cats->cats_ids[i_cat + 1];
++ }
++ cats->cats_idxs[cat_id] = -1;
++
++ --cats->n_a_cats;
++
++ return 0;
++}
++#endif
++
++/*!
++ \brief Insert scatter plot data .
++ Inserted scatt_data struct must have same type as cats struct (SC_SCATT_DATA or SC_SCATT_CONDITIONS).
++
++ \param cats pointer to scCats struct
++ \param cat_id id number of category.
++ \param scatt_id id number of scatter plot.
++
++ \return 0 on success
++ \return -1 on failure
++ */
++int I_sc_insert_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
++{
++ int band_1, band_2, cat_idx, n_a_scatts;
++ struct scScatts * scatts;
++
++ if(cat_id < 0 || cat_id >= cats->n_cats)
++ return -1;
++
++ cat_idx = cats->cats_idxs[cat_id];
++ if(cat_idx < 0)
++ return -1;
++
++ if(scatt_id < 0 && scatt_id >= cats->n_scatts)
++ return -1;
++
++ scatts = cats->cats_arr[cat_idx];
++ if(scatts->scatt_idxs[scatt_id] >= 0)
++ return -1;
++
++ if(!scatt_data->b_conds_arr && cats->type == SC_SCATT_CONDITIONS)
++ return -1;
++
++ if(!scatt_data->scatt_vals_arr && cats->type == SC_SCATT_DATA)
++ return -1;
++
++ n_a_scatts = scatts->n_a_scatts;
++
++ scatts->scatt_idxs[scatt_id] = n_a_scatts;
++
++ 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;
++
++ scatts->scatts_arr[n_a_scatts] = scatt_data;
++ ++scatts->n_a_scatts;
++
++ return 0;
++}
++
++#if 0
++int I_sc_remove_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
++{
++ int cat_idx, scatt_idx, n_init_scatts, i_scatt;
++ struct scScatts * scatts;
++
++ if(cat_id < 0 && cat_id >= cats->n_cats)
++ return -1;
++
++ cat_idx = cats->cats_idxs[cat_id];
++ if(cat_idx < 0)
++ return -1;
++
++ if(scatt_id < 0 || scatt_id >= cats->n_scatts)
++ return -1;
++
++ scatts = cats->cats_arr[cat_idx];
++ if(scatts->scatt_idxs[scatt_id] < 0)
++ return -1;
++
++ scatt_data = scatts->scatts_arr[scatt_idx];
++
++ for(i_scatt = scatt_idx; i_scatt < scatts->n_a_scatts - 1; i_scatt++)
++ {
++ scatts->scatts_arr[i_scatt] = scatts->scatts_arr[i_scatt + 1];
++ scatts->scatts_bands[i_scatt * 2] = scatts->scatts_bands[(i_scatt + 1)* 2];
++ scatts->scatts_bands[i_scatt * 2 + 1] = scatts->scatts_bands[(i_scatt + 1) * 2 + 1];
++ }
++ scatts->scatts_arr[scatts->n_a_scatts] = NULL;
++
++ scatts->scatt_idxs[scatt_id] = -1;
++
++ scatt_data = scatts->scatts_arr[scatt_id];
++ scatts->n_a_scatts--;
++
++ return 0;
++}
++
++int I_sc_set_value(struct scCats * cats, int cat_id, int scatt_id, int value_idx, int value)
++{
++ int n_a_scatts = cats->cats_arr[cat_id]->n_a_scatts;
++ int cat_idx, scatt_idx, ret;
++
++ cat_idx = cats->cats_idxs[cat_id];
++ if(cat_idx < 0)
++ return -1;
++
++ if(cats->cats_arr[cat_idx]->scatt_idxs[scatt_id] < 0)
++ return -1;
++
++ cat_idx = cats->cats_idxs[cat_id];
++ scatt_idx = cats->cats_arr[cat_idx]->scatt_idxs[scatt_id];
++
++ I_scd_set_value(cats->cats_arr[cat_idx]->scatts_arr[scatt_idx], value_idx, value);
++
++ return 0;
++}
++#endif
++
++/*!
++ \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)
++{
++ 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)
++ scatt_data->scatt_vals_arr = (unsigned int *) data;
++ else {
++ scatt_data->scatt_vals_arr = (unsigned int *) G_malloc(n_vals * sizeof(unsigned int));
++ memset(scatt_data->scatt_vals_arr, 0, n_vals * sizeof(unsigned int));
++ }
++ scatt_data->b_conds_arr = NULL;
++ }
++ else if(type == SC_SCATT_CONDITIONS)
++ {
++ if(data)
++ scatt_data->b_conds_arr = (unsigned char *) data;
++ else {
++ scatt_data->b_conds_arr = (unsigned char *) G_malloc(n_vals * sizeof(unsigned char));
++ memset(scatt_data->b_conds_arr, 0, n_vals * sizeof(unsigned char));
++ }
++ scatt_data->scatt_vals_arr = NULL;
++ }
++
++ 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)
++{
++
++ Rast_get_range_min_max(&(scatt_data->band_1_range), band_1_min, band_2_min);
++ Rast_get_range_min_max(&(scatt_data->band_2_range), band_2_min, band_2_max);
++
++ return;
++}
++s
++void * I_scd_get_data_ptr(struct scdScattData * scatt_data)
++{
++ if(!scatt_data->b_conds_arr)
++ return scatt_data->b_conds_arr;
++ else if(!scatt_data->scatt_vals_arr)
++ return scatt_data->scatt_vals_arr;
++
++ return NULL;
++}
++
++int I_scd_set_value(struct scdScattData * scatt_data, unsigned int val_idx, unsigned int val)
++{
++ if(val_idx < 0 && val_idx > scatt_data->n_vals)
++ return -1;
++
++ if(scatt_data->b_conds_arr)
++ scatt_data->b_conds_arr[val_idx] = val;
++ else if(scatt_data->scatt_vals_arr)
++ scatt_data->scatt_vals_arr[val_idx] = val;
++ else
++ return -1;
++
++ return 0;
++}
++#endif
Index: lib/imagery/scatt.c
===================================================================
--- lib/imagery/scatt.c (revision 0)
+++ lib/imagery/scatt.c (working copy)
-@@ -0,0 +1,610 @@
+@@ -0,0 +1,696 @@
+/*!
+ \file lib/imagery/scatt.c
+
@@ -3239,14 +4100,24 @@
+#include <string.h>
+
+
-+static const int CAT_RAST_SCATT_SEL = 2;
-+static const int CAT_RAST_RAST_SEL = 1;
-+static const int CAT_RAST_NULL = 0;
++/*!
++ \brief Create pgm header.
+
++ Scatter plot internally generates pgm files. These pns has header in format created by this function.
++
++ \param region - region to be pgm header generated for
++ \param [out] header - header pgm
++ */
+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
++ */
+int I_create_cat_rast(struct Cell_head * cat_rast_region, const char * cat_rast)
+{
+ FILE * f_cat_rast;
@@ -3274,7 +4145,6 @@
+
+ for(i_row = 0; i_row < cat_rast_region->rows; i_row++) {
+ fwrite(row_data, sizeof(unsigned char), (cat_rast_region->cols)/sizeof(unsigned char), f_cat_rast);
-+ // TODO when code will be paralelized put it out of the loop
+ if (ferror(f_cat_rast))
+ {
+ fclose(f_cat_rast);
@@ -3289,10 +4159,20 @@
+
+static int print_reg(struct Cell_head * intersec, const char * pref)
+{
-+ G_message("%s:\n n:%f\ns:%f\ne:%f\nw:%f\nns_res:%f\new_res:%f", pref, intersec->north, intersec->south,
++ G_debug(0, "%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);
+}
+
++/*!
++ \brief Find intersection region of two regions.
++
++ \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)
++
++ \return 0 if interection exists
++ \return -1 if regions does not intersect
++ */
+static int regions_intersecion(struct Cell_head * A, struct Cell_head * B, struct Cell_head * intersec)
+{
+
@@ -3320,17 +4200,33 @@
+
+}
+
++/*!
++ \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 [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
++
++ \return 0 if interection exists
++ \return -1 if regions do not intersect
++*/
+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)
+{
+ float ns_res, ew_res;
+
+ struct Cell_head intersec;
+
-+ if(A->ns_res != B->ns_res)
++ /* 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;
++ }
+
-+ if(A->ew_res != B->ew_res)
++ 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;
++ }
+
+ ns_res = A->ns_res;
+ ew_res = A->ew_res;
@@ -3353,7 +4249,16 @@
+ return 0;
+}
+
++/*!
++ \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
+
++ \return 0 on success
++ \return -1 on failure
++*/
+int I_insert_patch_to_cat_rast(const char * patch_rast, struct Cell_head * cat_rast_region, const char * cat_rast)
+{
+
@@ -3365,9 +4270,9 @@
+ int fd_patch_rast, init_shift, step_shift;
+ unsigned char * patch_data;
+
-+ char * null_chunk;
++ char * null_chunk_row;
+
-+ //TODO G_free mapset (aslo in compute scatts)
++ //TODO G_free mapset (also in compute scatts)
+ const char *mapset;
+
+ struct Cell_head patch_lines, cat_rast_lines;
@@ -3376,15 +4281,14 @@
+
+ f_cat_rast = fopen(cat_rast, "rb+");
+ if(!f_cat_rast)
-+ return -10;
-+
-+
++ return -1;
++
+ /* TODO */
+ head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
+
+ if ((mapset = G_find_raster2(patch_rast,"")) == NULL) {
+ fclose(f_cat_rast);
-+ return -2;
++ return -1;
+ }
+
+ Rast_get_cellhd(patch_rast, mapset, &patch_region);
@@ -3392,10 +4296,10 @@
+
+ if ((fd_patch_rast = Rast_open_old(patch_rast, mapset)) < 0) {
+ fclose(f_cat_rast);
-+ return -3;
++ return -1;
+ }
+
-+ null_chunk = Rast_allocate_null_buf();
++ null_chunk_row = Rast_allocate_null_buf();
+
+ if(get_rows_and_cols_bounds(cat_rast_region, &patch_region, &cat_rast_bounds, &patch_bounds) == -1) return -1;
+
@@ -3408,18 +4312,18 @@
+
+ if(fseek(f_cat_rast, init_shift, SEEK_SET) != 0) {
+ G_message("seek failed");
-+ return -4;
++ return -1;
+ }
+
+ step_shift = cat_rast_region->cols - ncols;
+
+ for(i_row = 0; i_row < nrows; i_row++) {
-+ Rast_get_null_value_row (fd_patch_rast, null_chunk, i_row + patch_bounds.north);
++ Rast_get_null_value_row (fd_patch_rast, null_chunk_row, i_row + patch_bounds.north);
+
+ for(i_col = 0; i_col < ncols; i_col++) {
+ patch_col = patch_bounds.west + i_col;
+
-+ if(null_chunk[patch_col] != 1)
++ if(null_chunk_row[patch_col] != 1)
+ patch_data[i_col] = 1 & 255;
+ else {
+ patch_data[i_col] = 0 & 255;
@@ -3429,29 +4333,38 @@
+ fwrite(patch_data, sizeof(unsigned char), (ncols)/sizeof(unsigned char), f_cat_rast);
+ if (ferror(f_cat_rast))
+ {
-+ G_free(null_chunk);
++ G_free(null_chunk_row);
+ fclose(f_cat_rast);
-+ return -5;
++ return -1;
+ }
+ if(fseek(f_cat_rast, step_shift, SEEK_CUR) != 0) {
+ G_message("seek failed");
-+ return -6;
++ return -1;
+ }
+ }
+
+ Rast_close(fd_patch_rast);
-+ G_free(null_chunk);
++ G_free(null_chunk_row);
+ fclose(f_cat_rast);
+ return 0;
+}
+
-+static inline void update_cat_scatt_plt(CELL ** chunks, char ** null_chunks, int chunk_size, unsigned short * belongs_pix, struct scScatts * scatts)
++/*!
++ \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 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
++*/
++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)
+{
-+ int band_axis_1, band_axis_2, i_scatt, array_idx, cat_idx, i_chunks_pix, max_arr_idx;
++ int band_axis_1, band_axis_2, i_scatt, array_idx, cat_idx, i_chunk_rows_pix, max_arr_idx;
+
-+ CELL * b_1_chunks;
-+ CELL * b_2_chunks;
-+ char * band_1_null_chunks,* band_2_null_chunks;
++ CELL * b_1_chunk_rows;
++ CELL * b_2_chunk_rows;
++ char * band_1_null_chunk_rows,* band_2_null_chunk_rows;
+
+ struct Range b_1_range, b_2_range;
+ int b_1_range_size;
@@ -3460,11 +4373,11 @@
+
+ for(i_scatt = 0; i_scatt < scatts->n_a_scatts; i_scatt++)
+ {
-+ b_1_chunks = chunks[scatts_bands[i_scatt * 2]];
-+ b_2_chunks = chunks[scatts_bands[i_scatt * 2 + 1]];
++ b_1_chunk_rows = chunk_rows[scatts_bands[i_scatt * 2]];
++ b_2_chunk_rows = chunk_rows[scatts_bands[i_scatt * 2 + 1]];
+
-+ band_1_null_chunks = null_chunks[scatts_bands[i_scatt * 2]];
-+ band_2_null_chunks = null_chunks[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_range = scatts->scatts_arr[i_scatt]->band_1_range;
+ b_2_range = scatts->scatts_arr[i_scatt]->band_2_range;
@@ -3472,14 +4385,14 @@
+ 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_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
++ for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
+ {
-+ if(!belongs_pix[i_chunks_pix] ||
-+ band_1_null_chunks[i_chunks_pix] == 1 ||
-+ band_2_null_chunks[i_chunks_pix] == 1)
++ 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)
+ continue;
+
-+ array_idx = b_1_chunks[i_chunks_pix] - b_1_range.min + (b_2_chunks[i_chunks_pix] - b_2_range.min) * b_1_range_size;
++ 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;
+
+ if(array_idx < 0 || array_idx >= max_arr_idx) {
+ G_warning ("pixel out of range");
@@ -3490,15 +4403,32 @@
+ }
+}
+
-+static inline int compute_scatts_from_chunk(struct scCats * scatt_plts, struct scCats * scatt_conds,
-+ CELL ** chunks, char ** null_chunks, int chunk_size, FILE ** f_cats_rasts_in,
-+ FILE ** f_cats_rasts_out, struct Cell_head *region, int i_chunk)
++/*!
++ \brief Computes scatter plots data from chunk_rows.
++
++ \param scatts pointer to scScatts struct of type SC_SCATT_DATA, where are computed scatter plots stored
++ \param scatt_conds pointer to scScatts struct of type SC_SCATT_CONDITIONS, where are selected areas (condtitions)stored
++
++ \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 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)
+{
+
-+ int i_chunks_pix, i_cat, i_scatt, n_a_scatts, i_cond;
++ int i_chunk_rows_pix, i_cat, i_scatt, n_a_scatts, i_cond;
+ int cat_id, scatt_plts_cat_idx, array_idx, max_arr_idx;
-+ char * band_1_null_chunks,* band_2_null_chunks;
-+
++ char * band_1_null_chunk_rows,* band_2_null_chunk_rows;
++ CELL * cat_rast_row;
++
+ struct scScatts * scatts_conds;
+ struct scScatts * scatt_plts_scatts;
+ struct scdScattData * conds;
@@ -3509,12 +4439,13 @@
+ int * scatts_bands;
+ struct scdScattData ** scatts_arr;
+
-+ CELL * b_1_chunks;
-+ CELL * b_2_chunks;
++ CELL * b_1_chunk_rows;
++ CELL * b_2_chunk_rows;
+ unsigned char * i_scatt_conds;
+
-+ unsigned short * belongs_pix = (unsigned short *) G_malloc(chunk_size * sizeof(unsigned short));
-+ unsigned char * rast_pixs = (unsigned char *) G_malloc(chunk_size * sizeof(unsigned char));
++ 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));
++ cat_rast_row = Rast_allocate_c_buf();
+
+ for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
+ {
@@ -3522,49 +4453,49 @@
+
+ cat_id = scatt_conds->cats_ids[i_cat];
+
-+ scatt_plts_cat_idx = scatt_plts->cats_idxs[cat_id];
++ scatt_plts_cat_idx = scatts->cats_idxs[cat_id];
+ if(scatt_plts_cat_idx < 0)
+ continue;
+
-+ scatt_plts_scatts = scatt_plts->cats_arr[scatt_plts_cat_idx];
++ scatt_plts_scatts = scatts->cats_arr[scatt_plts_cat_idx];
+
-+ G_zero(belongs_pix, chunk_size * sizeof(unsigned short));
++ G_zero(belongs_pix, chunk_row_size * sizeof(unsigned short));
+
-+ if(!scatts_conds->n_a_scatts && !f_cats_rasts_in[i_cat]) {
++ 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_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
-+ belongs_pix[i_chunks_pix] = 1;
++ for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
++ belongs_pix[i_chunk_rows_pix] = 1;
+ }
+ }
+ else
+ {
+ scatts_bands = scatts_conds->scatts_bands;
+
-+ if(f_cats_rasts_in[i_cat])
++ if(f_cats_rasts_conds[i_cat])
+
-+ fread(rast_pixs, sizeof(unsigned char), (chunk_size)/sizeof(unsigned char), f_cats_rasts_in[i_cat]);
-+ if (ferror(f_cats_rasts_in[i_cat]))
++ fread(rast_pixs, sizeof(unsigned char), (chunk_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.");
+ return -1;
+ }
-+ for(i_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
++ for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
+ {
-+ if(rast_pixs[i_chunks_pix] != 0 & 255)
-+ belongs_pix[i_chunks_pix] = 1;
++ if(rast_pixs[i_chunk_rows_pix] != 0 & 255)
++ belongs_pix[i_chunk_rows_pix] = 1;
+ }
+
+ // test every defined conditions in scatter plots
+ for(i_scatt = 0; i_scatt < scatts_conds->n_a_scatts; i_scatt++)
+ {
-+ b_1_chunks = chunks[scatts_bands[i_scatt * 2]];
-+ b_2_chunks = chunks[scatts_bands[i_scatt * 2 + 1]];
++ b_1_chunk_rows = chunk_rows[scatts_bands[i_scatt * 2]];
++ b_2_chunk_rows = chunk_rows[scatts_bands[i_scatt * 2 + 1]];
+
-+ band_1_null_chunks = null_chunks[scatts_bands[i_scatt * 2]];
-+ band_2_null_chunks = null_chunks[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]];
+
+ i_scatt_conds = scatts_conds->scatts_arr[i_scatt]->b_conds_arr;
+
@@ -3576,49 +4507,48 @@
+ 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_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
++ for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
+ {
-+ if(belongs_pix[i_chunks_pix] ||
-+ band_1_null_chunks[i_chunks_pix] == 1 ||
-+ band_2_null_chunks[i_chunks_pix] == 1)
++ 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)
+ continue;
+
-+ array_idx = b_1_chunks[i_chunks_pix] - b_1_range.min + (b_2_chunks[i_chunks_pix] - b_2_range.min) * b_1_range_size;
++ 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 */
+ if(array_idx < 0 || array_idx >= max_arr_idx) {
+ G_warning ("pixel out of range");
+ continue;
+ }
+ if(i_scatt_conds[array_idx])
-+ belongs_pix[i_chunks_pix] = 1;
++ belongs_pix[i_chunk_rows_pix] = 1;
+ }
+ }
+ }
+
-+ if(f_cats_rasts_out[i_cat]) {
-+ for(i_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
-+ rast_pixs[i_chunks_pix] = belongs_pix[i_chunks_pix] & 255;
++ if(fd_cats_rasts[i_cat] >= 0) {
++ Rast_set_null_value(cat_rast_row, Rast_window_cols(), CELL_TYPE);
+
-+ fwrite(rast_pixs, sizeof(unsigned char), (chunk_size)/sizeof(unsigned char), f_cats_rasts_out[i_cat]);
-+ // TODO when code will be paralelized put it out of the loop
-+ if (ferror(f_cats_rasts_out[i_cat]))
-+ {
-+ G_free(rast_pixs);
-+ G_free(belongs_pix);
-+ G_debug(3, "Unable to write into file.");
-+ return -1;
-+ }
++ 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];
++
++ Rast_put_c_row (fd_cats_rasts[i_cat], cat_rast_row);
+ }
+
-+ update_cat_scatt_plt(chunks, null_chunks, chunk_size, belongs_pix, scatt_plts_scatts);
++ update_cat_scatt_plts(chunk_rows, null_chunk_rows, chunk_row_size, belongs_pix, scatt_plts_scatts);
+ }
+
++ G_free(cat_rast_row);
+ G_free(rast_pixs);
+ G_free(belongs_pix);
+
+ return 0;
+}
+
++/*!
++ \brief Get list if bands needed to be opened for analysis from scCats struct.
++*/
+static void get_needed_bands(struct scCats * cats, int * b_needed_bands)
+{
+ // results in b_needed_bands - array of bools - if item has value 1, band (defined by item index) is needed to be opened
@@ -3637,8 +4567,11 @@
+ return;
+}
+
-+static void free_compute_scatts_data(int * fd_bands, CELL ** chunks, char ** null_chunks, int * n_a_bands, int * bands_ids,
-+ FILE ** f_cats_rasts_in, FILE ** f_cats_rasts_out, int n_a_cats)
++/*!
++ \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,
++ int * fd_cats_rasts, FILE ** f_cats_rasts_conds, int n_a_cats)
+{
+ int i, band_id;
+
@@ -3647,25 +4580,27 @@
+ band_id = bands_ids[i];
+ if(band_id >= 0) {
+ Rast_close(fd_bands[i]);
-+ G_free(chunks[band_id]);
-+ G_free(null_chunks[band_id]);
++ G_free(chunk_rows[band_id]);
++ G_free(null_chunk_rows[band_id]);
+ }
+ }
-+
-+ if(f_cats_rasts_in)
++
++ if(f_cats_rasts_conds)
+ for(i = 0; i < n_a_cats; i++)
-+ if(f_cats_rasts_in[i])
-+ fclose(f_cats_rasts_in[i]);
++ if(f_cats_rasts_conds[i])
++ fclose(f_cats_rasts_conds[i]);
+
-+ if(f_cats_rasts_out)
++ if(fd_cats_rasts)
+ for(i = 0; i < n_a_cats; i++)
-+ if(f_cats_rasts_out[i])
-+ fclose(f_cats_rasts_out[i]);
++ if(fd_cats_rasts[i] >= 0)
++ Rast_close(fd_cats_rasts[i]);
+
+}
+
-+
-+static int open_cats_rasts_files(const char ** cats_rasts, int n_a_cats, int * cats_ids, const char * mode, FILE ** f_cats_rasts)
++/*!
++ \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;
+
@@ -3674,17 +4609,20 @@
+ id_cat = cats_ids[i_cat];
+
+ if(cats_rasts[id_cat]) {
-+ f_cats_rasts[i_cat] = fopen(cats_rasts[id_cat], mode);
-+ if(!f_cats_rasts[i_cat]) return -1;
++ fd_cats_rasts[i_cat] = fopen(cats_rasts[id_cat], mode);
++ if(!fd_cats_rasts[i_cat]) return -1;
+ }
+ else
-+ f_cats_rasts[i_cat] = NULL;
++ fd_cats_rasts[i_cat] = NULL;
+ }
+
+ return 0;
+}
+
-+static int cats_rasts_write_header(int n_a_cats, struct Cell_head * region, FILE ** f_cats_rasts)
++/*!
++ \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
@@ -3693,37 +4631,49 @@
+
+ for(i_cat = 0; i_cat < n_a_cats; i_cat++)
+ {
-+ if(!f_cats_rasts[i_cat])
++ if(!fd_cats_rasts[i_cat])
+ continue;
+
-+ fwrite(cat_rast_header, sizeof(char), head_nchars/sizeof(char), f_cats_rasts[i_cat]);
-+ if (ferror(f_cats_rasts[i_cat])) return -1;
++ 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;
+
+}
+
-+//TODO change name: I_UpdateScattData???
++/*!
++ \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 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
++*/
+int I_compute_scatts(struct Cell_head *region, struct scCats * scatt_conds, const char ** bands,
-+ int n_bands, struct scCats * scatt_plts, const char ** cats_rasts_in, const char ** cats_rasts_out)
-+{/*scatt_plts must be zeros! */
-+ if (n_bands != scatt_plts->n_bands ||
++ int n_bands, const char ** cats_rasts_conds, struct scCats * scatts, const char ** cats_rasts)
++{
++ if (n_bands != scatts->n_bands ||
+ n_bands != scatt_conds->n_bands)
-+ return -1;
++ return -4;
+
+ const char *mapset;
++ char header[1024];
+
-+ FILE * f_cats_rasts_out[scatt_conds->n_a_cats];
-+ FILE * f_cats_rasts_in[scatt_conds->n_a_cats];
++ int fd_cats_rasts[scatt_conds->n_a_cats];
++ FILE * f_cats_rasts_conds[scatt_conds->n_a_cats];
+
-+ CELL * chunks[n_bands];
-+ char * null_chunks[n_bands];
++ CELL * chunk_rows[n_bands];
++ char * null_chunk_rows[n_bands];
+
+ RASTER_MAP_TYPE data_type;
+
+ int nrows, i_band, id_band, n_a_bands, band_id,
-+ chunk_size, i, i_chunk, i_row, head_nchars, i_cat;
++ chunk_row_size, i, i_row, head_nchars, i_cat, id_cat;
+ int fd_bands[n_bands];
+ for(i_band = 0; i_band < n_bands; i_band++)
+ fd_bands[i_band] = -1;
@@ -3736,7 +4686,7 @@
+ memset(b_needed_bands, 0, (size_t)n_bands * sizeof(int));
+
+ get_needed_bands(scatt_conds, &b_needed_bands[0]);
-+ get_needed_bands(scatt_plts, &b_needed_bands[0]);
++ get_needed_bands(scatts, &b_needed_bands[0]);
+
+ Rast_set_window(region);
+
@@ -3749,15 +4699,15 @@
+
+ /* TODO solve returns*/
+ if ((mapset = G_find_raster2(bands[id_band],"")) == NULL) {
-+ free_compute_scatts_data(&fd_bands[0], &chunks[0], &null_chunks[0], &n_a_bands,
++ 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 -1;
++ return -4;
+ }
+
+ if ((fd_bands[n_a_bands] = Rast_open_old(bands[id_band], mapset)) < 0) {
-+ free_compute_scatts_data(&fd_bands[0], &chunks[0], &null_chunks[0], &n_a_bands,
++ 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 -1;
++ return -5;
+ }
+
+ //TODO check data type, minimum and maximum value
@@ -3766,8 +4716,8 @@
+ // return -1;
+
+ //What happens if it is not CELL tyoe
-+ chunks[id_band] = Rast_allocate_c_buf();
-+ null_chunks[id_band] = Rast_allocate_null_buf();
++ chunk_rows[id_band] = Rast_allocate_c_buf();
++ null_chunk_rows[id_band] = Rast_allocate_null_buf();
+
+ bands_ids[n_a_bands] = id_band;
+
@@ -3775,33 +4725,30 @@
+ }
+ }
+
-+ if (open_cats_rasts_files(cats_rasts_out, scatt_conds->n_a_cats, scatt_conds->cats_ids, "wb", f_cats_rasts_out) != 0) {
-+ free_compute_scatts_data(&fd_bands[0], &chunks[0], &null_chunks[0], &n_a_bands,
-+ &bands_ids[0], &f_cats_rasts_out[0], NULL, scatt_conds->n_a_cats);
-+ return -1;
++ for(i_cat = 0; i_cat < scatts->n_a_cats; i_cat++)
++ {
++ id_cat = scatts->cats_ids[i_cat];
++ if(cats_rasts[id_cat]) {
++ fd_cats_rasts[i_cat] = Rast_open_new(cats_rasts[id_cat], CELL_TYPE);
++ }
++ else
++ fd_cats_rasts[i_cat] = -1;
+ }
+
-+ head_nchars = cats_rasts_write_header(scatt_conds->n_a_cats, region, f_cats_rasts_out);
-+ if (head_nchars < 0) {
-+ free_compute_scatts_data(&fd_bands[0], &chunks[0], &null_chunks[0], &n_a_bands,
-+ &bands_ids[0], &f_cats_rasts_out[0], NULL, scatt_conds->n_a_cats);
-+ return -1;
-+ }
++ head_nchars = get_cat_rast_header(region, header);
+
-+ if (open_cats_rasts_files(cats_rasts_in, scatt_conds->n_a_cats, scatt_conds->cats_ids, "rb", f_cats_rasts_in) != 0) {
-+ free_compute_scatts_data(&fd_bands[0], &chunks[0], &null_chunks[0], &n_a_bands,
-+ &bands_ids[0], &f_cats_rasts_out[0], &f_cats_rasts_in[0], scatt_conds->n_a_cats);
-+ return -1;
++ 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;
+ }
+
+ for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
-+ if(f_cats_rasts_in[i_cat])
-+ fseek(f_cats_rasts_in[i_cat] , head_nchars, SEEK_SET);
++ if(f_cats_rasts_conds[i_cat])
++ fseek(f_cats_rasts_conds[i_cat] , head_nchars, SEEK_SET);
+
-+ i_chunk = 0;
-+
+ nrows = Rast_window_rows();
-+ chunk_size = Rast_window_cols();
++ chunk_row_size = Rast_window_cols();
+
+ for (i_row = 0; i_row < nrows; i_row++)
+ {
@@ -3809,538 +4756,19 @@
+ {
+ band_id = bands_ids[i_band];
+ G_debug(3, "Reading data for band %d", band_id);
-+ Rast_get_c_row(fd_bands[i_band], chunks[band_id], i_row);
-+ Rast_get_null_value_row (fd_bands[i_band], null_chunks[band_id], i_row);
++ 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);
+ }
-+ if(compute_scatts_from_chunk(scatt_plts, scatt_conds, chunks, null_chunks, chunk_size, &f_cats_rasts_in[0], &f_cats_rasts_out[0], region, i_chunk) == -1)
++ 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)
+ {
-+ free_compute_scatts_data(&fd_bands[0], &chunks[0], &null_chunks[0], &n_a_bands,
-+ &bands_ids[0], &f_cats_rasts_out[0], &f_cats_rasts_in[0], 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);
++ return -3;
+ }
+
+ }
-+ free_compute_scatts_data(&fd_bands[0], &chunks[0], &null_chunks[0], &n_a_bands,
-+ &bands_ids[0], &f_cats_rasts_out[0], &f_cats_rasts_in[0], scatt_conds->n_a_cats);
++ 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 0;
+}
\ No newline at end of file
-Index: lib/imagery/scatt_sccats.c
-===================================================================
---- lib/imagery/scatt_sccats.c (revision 0)
-+++ lib/imagery/scatt_sccats.c (working copy)
-@@ -0,0 +1,342 @@
-+/*!
-+ \file lib/imagery/scatt_cat_rast.c
-+
-+ \brief Imagery library - functions for wx Scatter Plot Tool.
-+
-+ Low level functions used by wx Scatter Plot Tool.
-+
-+ Copyright (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.
-+
-+ \author Stepan Turek <stepan.turek at seznam.cz> (Mentor: Martin Landa)
-+ */
-+
-+#include <grass/raster.h>
-+#include <grass/imagery.h>
-+#include <grass/gis.h>
-+
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <math.h>
-+#include <string.h>
-+
-+//TODO split formulas to be more understandable
-+static void id_scatt_to_bands(const int scatt_id, const int n_bands, int * band_1, int * band_2)
-+{
-+ 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);
-+
-+ * band_2 = scatt_id - ((* band_1) * (2 * n_b1 + 1) - (* band_1) * (* band_1)) / 2 + (* band_1) + 1;
-+
-+ return;
-+}
-+
-+static void bands_to_id_scatt(const int band_1, const int band_2, 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;
-+
-+ return;
-+}
-+
-+void I_sc_init_cats(struct scCats * cats, int n_bands, int type)
-+{
-+ int i_cat;
-+
-+ cats->type = type;
-+
-+ cats->n_cats = 10;
-+ cats->n_a_cats = 0;
-+
-+ cats->n_bands = n_bands;
-+ cats->n_scatts = (n_bands - 1) * n_bands / 2;
-+
-+ cats->cats_arr = (struct scScatts **) malloc(cats->n_cats * sizeof(struct scScatts *));
-+ memset(cats->cats_arr, 0, cats-> n_cats * sizeof(struct scScatts *));
-+
-+ cats->cats_ids = (int *) malloc(cats->n_cats * sizeof(int));
-+ cats->cats_idxs =(int *) malloc(cats->n_cats * sizeof(int));
-+
-+ for(i_cat = 0; i_cat < cats->n_cats; i_cat++)
-+ cats->cats_idxs[i_cat] = -1;
-+
-+ return;
-+}
-+
-+void I_sc_free_cats(struct scCats * cats)
-+{
-+ int i_cat;
-+
-+ for(i_cat = 0; i_cat < cats->n_a_cats; i_cat++)
-+ {
-+ if(cats->cats_arr[i_cat])
-+ {
-+ free(cats->cats_arr[i_cat]->scatt_idxs);
-+ free(cats->cats_arr[i_cat]->scatts_bands);
-+ free(cats->cats_arr[i_cat]->scatts_arr);
-+ free(cats->cats_arr[i_cat]);
-+ }
-+ }
-+
-+ free(cats->cats_ids);
-+ free(cats->cats_idxs);
-+ free(cats->cats_arr);
-+
-+ cats->n_cats = 0;
-+ cats->n_a_cats = 0;
-+ cats->n_bands = 0;
-+ cats->n_scatts = 0;
-+ cats->type = -1;
-+
-+ return;
-+}
-+
-+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;
-+}
-+
-+int I_sc_add_cat(struct scCats * cats, int cat_id)
-+{
-+ int i_scatt;
-+ int n_a_cats = cats->n_a_cats;
-+
-+ if(cat_id < 0 || cat_id >= cats->n_cats)
-+ return -1;
-+
-+ 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;
-+
-+ cats->cats_arr[n_a_cats] = (struct scScatts *) malloc(sizeof(struct scScatts));
-+
-+ cats->cats_arr[n_a_cats]->scatts_arr = (struct scdScattData **) malloc(cats->n_scatts * sizeof(struct scdScattData *));
-+ memset((cats->cats_arr[n_a_cats]->scatts_arr), 0, cats->n_scatts * sizeof(struct scdScattData *));
-+
-+ cats->cats_arr[n_a_cats]->n_a_scatts = 0;
-+
-+ cats->cats_arr[n_a_cats]->scatts_bands = (int *) malloc(cats->n_scatts * 2 * sizeof(int));
-+
-+ cats->cats_arr[n_a_cats]->scatt_idxs = (int *) malloc(cats->n_scatts * sizeof(int));
-+ for(i_scatt = 0; i_scatt < cats->n_scatts; i_scatt++)
-+ cats->cats_arr[n_a_cats]->scatt_idxs[i_scatt] = -1;
-+
-+ ++cats->n_a_cats;
-+
-+ return 0;
-+}
-+
-+int I_sc_delete_cat(struct scCats * cats, int cat_id)
-+{
-+ int cat_idx, i_cat;
-+
-+ if(cat_id < 0 || cat_id >= cats->n_cats)
-+ return -1;
-+
-+ cat_idx = cats->cats_idxs[cat_id];
-+ if(cat_idx < 0)
-+ return -1;
-+
-+ free(cats->cats_arr[cat_idx]->scatt_idxs);
-+ free(cats->cats_arr[cat_idx]->scatts_bands);
-+ free(cats->cats_arr[cat_idx]->scatts_arr);
-+ free(cats->cats_arr[cat_idx]);
-+
-+ for(i_cat = cat_idx; i_cat < cats->n_a_cats - 1; i_cat++)
-+ {
-+ cats->cats_arr[i_cat] = cats->cats_arr[i_cat + 1];
-+ cats->cats_ids[i_cat] = cats->cats_ids[i_cat + 1];
-+ }
-+ cats->cats_idxs[cat_id] = -1;
-+
-+ --cats->n_a_cats;
-+
-+ return 0;
-+}
-+
-+
-+int I_sc_insert_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
-+{
-+ int band_1, band_2, cat_idx, n_a_scatts;
-+ struct scScatts * scatts;
-+
-+ if(cat_id < 0 || cat_id >= cats->n_cats)
-+ return -1;
-+
-+ cat_idx = cats->cats_idxs[cat_id];
-+ if(cat_idx < 0)
-+ return -1;
-+
-+ if(scatt_id < 0 && scatt_id >= cats->n_scatts)
-+ return -1;
-+
-+ scatts = cats->cats_arr[cat_idx];
-+ if(scatts->scatt_idxs[scatt_id] >= 0)
-+ return -1;
-+
-+ if(!scatt_data->b_conds_arr && cats->type == SC_SCATT_CONDITIONS)
-+ return -1;
-+
-+ if(!scatt_data->scatt_vals_arr && cats->type == SC_SCATT_DATA)
-+ return -1;
-+
-+ n_a_scatts = scatts->n_a_scatts;
-+
-+ scatts->scatt_idxs[scatt_id] = n_a_scatts;
-+
-+ 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;
-+
-+ scatts->scatts_arr[n_a_scatts] = scatt_data;
-+ ++scatts->n_a_scatts;
-+
-+ return 0;
-+}
-+
-+int I_sc_remove_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
-+{
-+ int cat_idx, scatt_idx, n_init_scatts, i_scatt;
-+ struct scScatts * scatts;
-+
-+ if(cat_id < 0 && cat_id >= cats->n_cats)
-+ return -1;
-+
-+ cat_idx = cats->cats_idxs[cat_id];
-+ if(cat_idx < 0)
-+ return -1;
-+
-+ if(scatt_id < 0 || scatt_id >= cats->n_scatts)
-+ return -1;
-+
-+ scatts = cats->cats_arr[cat_idx];
-+ if(scatts->scatt_idxs[scatt_id] < 0)
-+ return -1;
-+
-+ scatt_data = scatts->scatts_arr[scatt_idx];
-+
-+ for(i_scatt = scatt_idx; i_scatt < scatts->n_a_scatts - 1; i_scatt++)
-+ {
-+ scatts->scatts_arr[i_scatt] = scatts->scatts_arr[i_scatt + 1];
-+ scatts->scatts_bands[i_scatt * 2] = scatts->scatts_bands[(i_scatt + 1)* 2];
-+ scatts->scatts_bands[i_scatt * 2 + 1] = scatts->scatts_bands[(i_scatt + 1) * 2 + 1];
-+ }
-+ scatts->scatts_arr[scatts->n_a_scatts] = NULL;
-+
-+ scatts->scatt_idxs[scatt_id] = -1;
-+
-+ scatt_data = scatts->scatts_arr[scatt_id];
-+ scatts->n_a_scatts--;
-+
-+ return 0;
-+}
-+
-+int I_sc_set_value(struct scCats * cats, int cat_id, int scatt_id, int value_idx, int value)
-+{
-+ int n_a_scatts = cats->cats_arr[cat_id]->n_a_scatts;
-+ int cat_idx, scatt_idx, ret;
-+
-+ cat_idx = cats->cats_idxs[cat_id];
-+ if(cat_idx < 0)
-+ return -1;
-+
-+ if(cats->cats_arr[cat_idx]->scatt_idxs[scatt_id] < 0)
-+ return -1;
-+
-+ cat_idx = cats->cats_idxs[cat_id];
-+ scatt_idx = cats->cats_arr[cat_idx]->scatt_idxs[scatt_id];
-+
-+ I_scd_set_value(cats->cats_arr[cat_idx]->scatts_arr[scatt_idx], value_idx, value);
-+
-+ return 0;
-+}
-+
-+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)
-+{
-+ 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)
-+ scatt_data->scatt_vals_arr = (unsigned int *) data;
-+ else {
-+ scatt_data->scatt_vals_arr = (unsigned int *) malloc(n_vals * sizeof(unsigned int));
-+ memset(scatt_data->scatt_vals_arr, 0, n_vals * sizeof(unsigned int));
-+ }
-+ scatt_data->b_conds_arr = NULL;
-+ }
-+ else if(type == SC_SCATT_CONDITIONS)
-+ {
-+ if(data)
-+ scatt_data->b_conds_arr = (unsigned char *) data;
-+ else {
-+ scatt_data->b_conds_arr = (unsigned char *) malloc(n_vals * sizeof(unsigned char));
-+ memset(scatt_data->b_conds_arr, 0, n_vals * sizeof(unsigned char));
-+ }
-+ scatt_data->scatt_vals_arr = NULL;
-+ }
-+
-+ return;
-+}
-+
-+void I_scd_free_scatt_data(struct scdScattData * scatt_data)
-+{
-+
-+ free(scatt_data->b_conds_arr);
-+ free(scatt_data->scatt_vals_arr);
-+
-+ scatt_data = NULL;
-+
-+ return;
-+}
-+
-+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)
-+{
-+
-+ Rast_get_range_min_max(&(scatt_data->band_1_range), band_1_min, band_2_min);
-+ Rast_get_range_min_max(&(scatt_data->band_2_range), band_2_min, band_2_max);
-+
-+ return;
-+}
-+
-+void * I_scd_get_data_ptr(struct scdScattData * scatt_data)
-+{
-+ if(!scatt_data->b_conds_arr)
-+ return scatt_data->b_conds_arr;
-+ else if(!scatt_data->scatt_vals_arr)
-+ return scatt_data->scatt_vals_arr;
-+
-+ return NULL;
-+}
-+
-+int I_scd_set_value(struct scdScattData * scatt_data, unsigned int val_idx, unsigned int val)
-+{
-+ if(val_idx < 0 && val_idx > scatt_data->n_vals)
-+ return -1;
-+
-+ if(scatt_data->b_conds_arr)
-+ scatt_data->b_conds_arr[val_idx] = val;
-+ else if(scatt_data->scatt_vals_arr)
-+ scatt_data->scatt_vals_arr[val_idx] = val;
-+ else
-+ return -1;
-+
-+ return 0;
-+}
-Index: lib/vector/vedit/move.c
-===================================================================
---- lib/vector/vedit/move.c (revision 57336)
-+++ lib/vector/vedit/move.c (working copy)
-@@ -22,13 +22,16 @@
- \param List list of primitives to be moved
- \param move_x,move_y,move_z direction (move_z used only if map is 3D)
- \param snap enable snapping (see globals.h)
--
-+ \param new_ids list of newly assigned ids for features, which vertexes were moved,
-+ new_id corresponds to same position of id in List
-+ null pointer can be passed
-+
- \return number of modified primitives
- \return -1 on error
- */
- int Vedit_move_lines(struct Map_info *Map, struct Map_info **BgMap,
- int nbgmaps, struct ilist *List, double move_x,
-- double move_y, double move_z, int snap, double thresh)
-+ double move_y, double move_z, int snap, double thresh, struct ilist *new_ids)
- {
- struct line_pnts *Points;
- struct line_cats *Cats;
-@@ -84,6 +87,8 @@
- if (newline < 0) {
- return -1;
- }
-+ if(new_ids)
-+ Vect_list_append(new_ids, newline);
-
- nlines_moved++;
- }
-Index: lib/vector/vedit/vertex.c
-===================================================================
---- lib/vector/vedit/vertex.c (revision 57336)
-+++ lib/vector/vedit/vertex.c (working copy)
-@@ -26,7 +26,10 @@
- \param move_x,move_y,move_z direction (move_z is used when map is 3D)
- \param move_first move only first vertex found in the bounding box
- \param snap snapping mode (see vedit.h)
--
-+ \param new_ids list of newly assigned ids for features, which vertexes were moved,
-+ new_id corresponds to same position of id in List
-+ if feature was not rewritten new id is -1
-+ null pointer can be passed
- \return number of moved verteces
- \return -1 on error
- */
-@@ -34,11 +37,11 @@
- int nbgmaps, struct ilist *List,
- struct line_pnts *coord, double thresh_coords,
- double thresh_snap, double move_x, double move_y,
-- double move_z, int move_first, int snap)
-+ double move_z, int move_first, int snap, struct ilist *new_ids)
- {
- int nvertices_moved, nlines_modified, nvertices_snapped;
-
-- int i, j, k;
-+ int i, j, k, newline;
- int line, type, rewrite;
- int npoints;
- double east, north, dist;
-@@ -159,12 +162,17 @@
- } /* for each coord */
-
- if (rewrite) {
-- if (Vect_rewrite_line(Map, line, type, Points, Cats) < 0) {
-+ newline = Vect_rewrite_line(Map, line, type, Points, Cats);
-+ if (newline < 0) {
- return -1;
- }
-+ if(new_ids)
-+ Vect_list_append(new_ids, newline);
-
- nlines_modified++;
- }
-+ else if(new_ids)
-+ Vect_list_append(new_ids, -1);
- } /* for each selected line */
-
- /* destroy structures */
-@@ -187,12 +195,15 @@
- \param List list of lines
- \param coord points location
- \param thresh find line in given threshold
--
-+ \param new_ids list of newly assigned ids for features, which vertexes were moved,
-+ new_id corresponds to same position of id in List
-+ if feature was not rewritten new id is -1
-+ null pointer can be passed
- \return number of add verteces
- \return -1 on error
- */
- int Vedit_add_vertex(struct Map_info *Map, struct ilist *List,
-- struct line_pnts *coord, double thresh)
-+ struct line_pnts *coord, double thresh, struct ilist *new_ids)
- {
- int i, j;
- int type, line, seg;
-@@ -200,6 +211,7 @@
- double east, north, dist;
- double *x, *y, *z;
- double px, py;
-+ int newline;
-
- struct line_pnts *Points;
- struct line_cats *Cats;
-@@ -253,12 +265,17 @@
- /* rewrite the line */
- if (rewrite) {
- Vect_line_prune(Points);
-- if (Vect_rewrite_line(Map, line, type, Points, Cats) < 0) {
-+ newline = Vect_rewrite_line(Map, line, type, Points, Cats);
-+ if (newline < 0) {
- return -1;
- }
-+ if(new_ids)
-+ Vect_list_append(new_ids, newline);
-
- nlines_modified++;
- }
-+ else if(new_ids)
-+ Vect_list_append(new_ids, -1);
- } /* for each line */
-
- /* destroy structures */
-@@ -277,12 +294,15 @@
- \param List list of selected lines
- \param coord points location
- \param thresh threshold value to find a line
--
-+ \param new_ids list of newly assigned ids for features, which vertexes were moved,
-+ new_id corresponds to same position of id in List
-+ if feature was not rewritten new id is -1
-+ null pointer can be passed
- \return number of removed vertices
- \return -1 on error
- */
- int Vedit_remove_vertex(struct Map_info *Map, struct ilist *List,
-- struct line_pnts *coord, double thresh)
-+ struct line_pnts *coord, double thresh, struct ilist *new_ids)
- {
- int i, j, k;
- int type, line;
-@@ -290,6 +310,7 @@
- double east, north;
- double dist;
- double *x, *y, *z;
-+ int newline;
-
- struct line_pnts *Points;
- struct line_cats *Cats;
-@@ -336,12 +357,18 @@
-
- if (rewrite) {
- /* rewrite the line */
-- if (Vect_rewrite_line(Map, line, type, Points, Cats) < 0) {
-+ newline = Vect_rewrite_line(Map, line, type, Points, Cats);
-+ if (newline < 0) {
- return -1;
- }
-+ if(new_ids)
-+ Vect_list_append(new_ids, newline);
-
- nlines_modified++;
- }
-+ else if(new_ids)
-+ Vect_list_append(new_ids, -1);
-+
- } /* for each line */
-
- /* destroy structures */
More information about the grass-commit
mailing list