[GRASS-SVN] r57287 - sandbox/turek/scatter_plot
svn_grass at osgeo.org
svn_grass at osgeo.org
Fri Jul 26 18:36:53 PDT 2013
Author: turek
Date: 2013-07-26 18:36:53 -0700 (Fri, 26 Jul 2013)
New Revision: 57287
Added:
sandbox/turek/scatter_plot/testing_patch.diff
Removed:
sandbox/turek/scatter_plot/testing_pach.diff
Log:
file name type
Deleted: sandbox/turek/scatter_plot/testing_pach.diff
===================================================================
--- sandbox/turek/scatter_plot/testing_pach.diff 2013-07-27 01:33:01 UTC (rev 57286)
+++ sandbox/turek/scatter_plot/testing_pach.diff 2013-07-27 01:36:53 UTC (rev 57287)
@@ -1,4189 +0,0 @@
-Index: vector/v.edit/main.c
-===================================================================
---- vector/v.edit/main.c (revision 57285)
-+++ 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 57285)
-+++ include/imagery.h (working copy)
-@@ -135,6 +135,41 @@
-
- } IClass_statistics;
-
-+/* 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;
-+};
-+
-+struct scdScattData
-+{
-+ int n_vals;
-+ //TODO void pointer???
-+ unsigned int * b_conds_arr;
-+ unsigned int * scatt_vals_arr;
-+};
-+
- #define SIGNATURE_TYPE_MIXED 1
-
- #define GROUPFILE "CURGROUP"
-Index: include/defs/vedit.h
-===================================================================
---- include/defs/vedit.h (revision 57285)
-+++ include/defs/vedit.h (working copy)
-@@ -34,7 +34,7 @@
-
- /* 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: include/defs/imagery.h
-===================================================================
---- include/defs/imagery.h (revision 57285)
-+++ include/defs/imagery.h (working copy)
-@@ -110,6 +110,29 @@
- 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 I_scd_free_scatt_data(struct scdScattData *);
-+int I_scd_get_data_size(struct scdScattData *);
-+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 I_create_cat_rast(struct Cell_head *, const char *);
-+int I_insert_patch_to_cat_rast(const char *, struct Cell_head *, const char *);
-+
-+
- /* sig.c */
- int I_init_signatures(struct Signature *, int);
- int I_new_signature(struct Signature *);
-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,631 @@
-+"""!
-+ 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
-+
-+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
-+
-+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):
-+
-+ self.scatts_dt.AddScattPlot(scatt_id = scatt_id)
-+
-+ scatt_conds = self.scatt_conds_dt.GetData({0 : []})
-+ scatts = self.scatts_dt.GetData({0 : [scatt_id]})
-+
-+ 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)
-+ self.scatts_dt.SetData(scatts)
-+
-+ def SetEditCatData(self, cat_id, scatt_id, bbox, value):
-+
-+ 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
-+
-+ self.ComputeCatScatts([cat_id])
-+
-+ 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)
-+
-+ 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 = None
-+ self.bin_bands_f = []
-+
-+ self.region = {}
-+
-+ def GetRegion(self):
-+ return self.region
-+
-+ def Create(self, bands):
-+
-+ self.bands = None
-+ 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.region = self._parseRegion(region)
-+
-+ def GetBands(self):
-+ return self.bands
-+
-+ 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
-+
-+ self.max_n_cats = 10
-+
-+ self.vals = 256 * 256
-+
-+ 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
-+
-+ if self.type == 0:
-+ np_vals = np.zeros(self.vals, dtype = 'uint32')
-+ elif self.type == 1:
-+ #TODO solve proble with short
-+ np_vals = np.zeros(self.vals, dtype = 'uint32')
-+ else:
-+ return -1
-+
-+ np_vals.shape = (256, 256)#TODO hack do it general
-+
-+ self.cats[cat_id][scatt_id] = {
-+ 'np_vals' : np_vals
-+ }
-+
-+ return 1
-+
-+ 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']}
-+
-+ 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)
-+
-+ #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] = self.cats[cat_id][scatt_id]['np_vals']
-+
-+ 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 idScattToBands(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 BandsToidScatt(band_1, band_2, n_bands):
-+
-+ if band_2 < band_1:
-+ tmp = band_1
-+ band_1 = band_2
-+ band_2 = tmp
-+
-+
-+ n_b1 = n_bands - 1
-+
-+ scatt_id = (band_1 * (2 * n_b1 + 1) - band_1 * band_1) / 2 + band_2 - band_1 - 1
-+
-+ return scatt_id
-+
-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 @@
-+"""!
-+ at package scatt_plot.gthreading
-+
-+Classes:
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+
-+import os
-+import sys
-+import time
-+import threading
-+import Queue
-+
-+import wx
-+from core.gconsole import wxCmdRun, wxCmdDone, wxCmdPrepare
-+
-+class gThread(threading.Thread):
-+ """!Thread for GRASS commands"""
-+ requestId = 0
-+
-+ def __init__(self, receiver, requestQ=None, resultQ=None, **kwds):
-+ """!
-+ @param receiver event receiver (used in PostEvent)
-+ """
-+ threading.Thread.__init__(self, **kwds)
-+
-+ if requestQ is None:
-+ self.requestQ = Queue.Queue()
-+ else:
-+ self.requestQ = requestQ
-+
-+ if resultQ is None:
-+ self.resultQ = Queue.Queue()
-+ else:
-+ self.resultQ = resultQ
-+
-+ self.setDaemon(True)
-+
-+ self.receiver = receiver
-+ self._want_abort_all = False
-+
-+ self.start()
-+
-+ def Run(self, *args, **kwds):
-+ """!Run command in queue
-+
-+ @param args unnamed command arguments
-+ @param kwds named command arguments
-+
-+ @return request id in queue
-+ """
-+ gThread.requestId += 1
-+ self.requestQ.put((gThread.requestId, args, kwds))
-+
-+ return gThread.requestId
-+
-+ def GetId(self):
-+ """!Get id for next command"""
-+ return gThread.requestId + 1
-+
-+ def SetId(self, id):
-+ """!Set starting id"""
-+ gThread.requestId = id
-+
-+ def run(self):
-+ os.environ['GRASS_MESSAGE_FORMAT'] = 'gui'
-+ while True:
-+ requestId, args, kwds = self.requestQ.get()
-+ for key in ('callable', 'onDone', 'onPrepare', 'userData'):
-+ if key in kwds:
-+ vars()[key] = kwds[key]
-+ del kwds[key]
-+ else:
-+ vars()[key] = None
-+
-+ requestTime = time.time()
-+
-+ #if self._want_abort_all and self.requestCmd is not None:
-+ # self.requestCmd.abort()
-+ # if self.requestQ.empty():
-+ # self._want_abort_all = False
-+
-+ # prepare
-+ if self.receiver:
-+ event = wxCmdPrepare(type = 'method',
-+ time=requestTime,
-+ pid=requestId)
-+
-+ wx.PostEvent(self.receiver, event)
-+
-+ # run command
-+ event = wxCmdRun(type = 'method',
-+ pid=requestId)
-+
-+ wx.PostEvent(self.receiver, event)
-+
-+ time.sleep(.1)
-+
-+ ret = None
-+ exception = None
-+ #try:
-+ ret = vars()['callable'](*args, **kwds)
-+ #except Exception as e:
-+ # exception = e;
-+
-+ self.resultQ.put((requestId, ret))
-+
-+ time.sleep(.1)
-+
-+
-+ if self.receiver:
-+ event = wxCmdDone(type = 'cmd',
-+ kwds = kwds,
-+ args = args, #TODO expand args to kwds
-+ ret=ret,
-+ exception=exception,
-+ pid=requestId)
-+
-+ # send event
-+ wx.PostEvent(self.receiver, event)
-+
-+ def abort(self, abortall=True):
-+ """!Abort command(s)"""
-+ if abortall:
-+ self._want_abort_all = True
-+ if self.requestQ.empty():
-+ self._want_abort_all = False
-\ No newline at end of file
-Index: gui/wxpython/scatt_plot/dialogs.py
-===================================================================
---- gui/wxpython/scatt_plot/dialogs.py (revision 0)
-+++ gui/wxpython/scatt_plot/dialogs.py (working copy)
-@@ -0,0 +1,612 @@
-+"""!
-+ at package scatt_plot.dialogs
-+
-+ at brief GUI.
-+
-+Classes:
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+import os
-+import sys
-+
-+import wx
-+import wx.lib.mixins.listctrl as listmix
-+import wx.lib.flatnotebook as FN
-+import wx.aui
-+
-+from core import globalvar
-+from core.gcmd import GException, GError, RunCommand
-+
-+from gui_core.gselect import Select
-+from 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, BandsToidScatt
-+from scatt_plot.plots import ScatterPlotWidget
-+
-+
-+class ScattPlotMainDialog(wx.Dialog):
-+ 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))
-+
-+ #TODO remove iclass parameter
-+ 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)
-+
-+ # Fancy gui
-+ self._mgr = wx.aui.AuiManager(self)
-+ self._addPanes()
-+ self._mgr.Update()
-+
-+ 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)
-+
-+ dlgSize = (220, 400)
-+ self.SetMinSize(dlgSize)
-+ self.SetInitialSize(dlgSize)
-+
-+ #fix goutput's pane size (required for Mac OSX)
-+ #if self.gwindow:
-+ # self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
-+
-+ def _doLayout(self):
-+
-+ sizer = wx.BoxSizer(wx.VERTICAL)
-+
-+ sizer.Add(item = self.notebook, proportion = 1,
-+ flag = wx.EXPAND)
-+
-+ self.mainPanel.SetSizer(sizer)
-+
-+ sizer.Fit(self)
-+ self.Layout()
-+
-+ #TODO split to panel?
-+ def _createCategoryPage(self):
-+ catsPanel = wx.Panel(parent = self)
-+
-+
-+ self.notebook.AddPage(page = catsPanel,
-+ text=_('Categories'),
-+ name = 'categories')
-+
-+ 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)
-+
-+ AnalysisSizer = wx.BoxSizer(wx.VERTICAL)
-+
-+ catsSizer = wx.BoxSizer(wx.VERTICAL)
-+
-+ catsSizer.Add(item = self.toolbars['catsList'], proportion = 0)
-+ catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND)
-+
-+ catsPanel.SetSizer(catsSizer)
-+
-+ 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))
-+
-+ self._mgr.AddPane(self.mainPanel,
-+ wx.aui.AuiPaneInfo().
-+ Name("tabs").CaptionVisible(visible = False).
-+ Center().
-+ Dockable(False).
-+ CloseButton(False).Layer(0))
-+
-+ def OnCloseDialog(self, event):
-+ """!Close dialog"""
-+ self.scatt_mgr.CleanUp()
-+ self.Destroy()
-+
-+ def OnSettings(self, event):
-+ pass
-+
-+ def OnSetData(self, event):
-+
-+ dlg = SetDataDialog(parent=self)
-+
-+ if dlg.ShowModal() == wx.ID_OK:
-+ bands = dlg.GetBands()
-+ self.scatt_mgr.SetData(bands)
-+
-+ dlg.Destroy()
-+
-+
-+ 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()
-+
-+ def OnSettings(self, event):
-+ pass
-+
-+ def OnAddScattPl(self, event):
-+
-+ bands = self.scatt_mgr.GetBands()
-+ if not bands:
-+ GError(_('No data set for scatter plot.'))
-+ return
-+
-+ dlg = AddScattPlotDialog(parent = self, bands = bands)
-+
-+ if dlg.ShowModal() == wx.ID_OK:
-+ self.scatt_mgr.AddScattPlot(dlg.GetScattId())
-+
-+ dlg.Destroy()
-+
-+ def EditCatAdd(self):
-+ self._setEditCat(tool_name = 'editCatAdd')
-+
-+ def EditCatRemove(self):
-+ self._setEditCat(tool_name = 'editCatRemove')
-+
-+ def _setEditCat(self, tool_name):
-+
-+ 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.edit_cat_tools[i_tool_name]['toggle'] = False
-+
-+ toolbar = self.toolbars['catsList']
-+ toolbar.ToggleTool(vars(toolbar)[i_tool_name], False)
-+
-+ self.edit_cat_tools[tool_name]['toggle'] = True
-+ self.scatt_mgr.EditCat(edit_type = self.edit_cat_tools[tool_name]['type'])
-+ return
-+
-+ self.scatt_mgr.EditCat(edit_type = None)
-+ self.edit_cat_tools[tool_name]['toggle'] = False
-+
-+ def GetScattMgr(self):
-+ return self.scatt_mgr
-+
-+
-+class SetDataDialog(wx.Dialog):
-+
-+ def __init__(self, parent, id = wx.ID_ANY):
-+
-+ wx.Dialog.__init__(self, parent, title = ("Select imagery group "), id = id)
-+
-+ self.bands = []
-+
-+
-+ self._createWidgets()
-+ self.group.SetValue("testovaci_1")
-+
-+ 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.group = Select(parent = self, type = 'group',
-+ size = globalvar.DIALOG_GSELECT_SIZE)
-+
-+ # buttons
-+ self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
-+
-+ self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
-+
-+ self._layout()
-+
-+ def _layout(self):
-+
-+ border = wx.BoxSizer(wx.VERTICAL)
-+ dialogSizer = wx.BoxSizer(wx.VERTICAL)
-+
-+ regionSizer = wx.BoxSizer(wx.HORIZONTAL)
-+
-+ dialogSizer.Add(item = self._addSelectSizer(title = self.group_label,
-+ sel = self.group))
-+
-+ # buttons
-+ self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
-+
-+ self.btnsizer.Add(item = self.btn_close, proportion = 0,
-+ flag = wx.ALL | wx.ALIGN_CENTER,
-+ border = 10)
-+
-+ self.btnsizer.Add(item = self.btn_ok, proportion = 0,
-+ flag = wx.ALL | wx.ALIGN_CENTER,
-+ border = 10)
-+
-+ dialogSizer.Add(item = self.btnsizer, proportion = 0,
-+ flag = wx.ALIGN_CENTER)
-+
-+ border.Add(item = dialogSizer, proportion = 0,
-+ flag = wx.ALL, border = 5)
-+
-+ self.SetSizer(border)
-+ self.Layout()
-+ self.Fit()
-+
-+ # bindings
-+ self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
-+ self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
-+
-+ def _addSelectSizer(self, title, sel):
-+ """!Helper layout function.
-+ """
-+ selSizer = wx.BoxSizer(orient = wx.VERTICAL)
-+
-+ selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
-+ selTitleSizer.Add(item = title, proportion = 1,
-+ flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
-+
-+ selSizer.Add(item = selTitleSizer, proportion = 0,
-+ flag = wx.EXPAND)
-+
-+ selSizer.Add(item = sel, proportion = 1,
-+ flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
-+ border = 5)
-+
-+ return selSizer
-+
-+ def GetBands(self):
-+
-+ return self.bands
-+
-+ def OnClose(self, event):
-+ """!Close dialog
-+ """
-+ if not self.IsModal():
-+ self.Destroy()
-+ event.Skip()
-+
-+ def OnOk(self, event):
-+ """!
-+ """
-+ ret, stdout, err_msg = RunCommand("i.group",
-+ getErrorMsg = True,
-+ read = True,
-+ quiet = True,
-+ group = self.group.GetValue().strip(),
-+ flags = 'g')
-+
-+ if ret != 0:
-+ GError("%s module failed:\n%s" % ("<i.group>", err_msg))
-+ return
-+
-+ self.bands = stdout.split('\n')
-+
-+ 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()
-+
-+class AddScattPlotDialog(wx.Dialog):
-+
-+ def __init__(self, parent, bands, id = wx.ID_ANY):
-+
-+ wx.Dialog.__init__(self, parent, title = ("Add scatter plot"), id = id)
-+
-+ self.bands = bands
-+
-+ self.scatt_id = None
-+
-+ self._createWidgets()
-+
-+ def _createWidgets(self):
-+
-+ self.labels = {}
-+ self.params = {}
-+
-+ self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
-+
-+ self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+ choices = self.bands,
-+ style = wx.CB_READONLY, size = (350, 30))
-+
-+ self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 2:"))
-+
-+ self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+ choices = self.bands,
-+ style = wx.CB_READONLY, size = (350, 30))
-+
-+ # buttons
-+ self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
-+
-+ self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
-+
-+ self._layout()
-+
-+ def _layout(self):
-+
-+ border = wx.BoxSizer(wx.VERTICAL)
-+ dialogSizer = wx.BoxSizer(wx.VERTICAL)
-+
-+ regionSizer = wx.BoxSizer(wx.HORIZONTAL)
-+
-+ dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label,
-+ sel = self.band_1_ch))
-+
-+ dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label,
-+ sel = self.band_2_ch))
-+
-+ # buttons
-+ self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
-+
-+ self.btnsizer.Add(item = self.btn_close, proportion = 0,
-+ flag = wx.ALL | wx.ALIGN_CENTER,
-+ border = 10)
-+
-+ self.btnsizer.Add(item = self.btn_ok, proportion = 0,
-+ flag = wx.ALL | wx.ALIGN_CENTER,
-+ border = 10)
-+
-+ dialogSizer.Add(item = self.btnsizer, proportion = 0,
-+ flag = wx.ALIGN_CENTER)
-+
-+ border.Add(item = dialogSizer, proportion = 0,
-+ flag = wx.ALL, border = 5)
-+
-+ self.SetSizer(border)
-+ self.Layout()
-+ self.Fit()
-+
-+ # bindings
-+ self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
-+ self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
-+
-+ def _addSelectSizer(self, title, sel):
-+ """!Helper layout function.
-+ """
-+ selSizer = wx.BoxSizer(orient = wx.VERTICAL)
-+
-+ selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
-+ selTitleSizer.Add(item = title, proportion = 1,
-+ flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
-+
-+ selSizer.Add(item = selTitleSizer, proportion = 0,
-+ flag = wx.EXPAND)
-+
-+ selSizer.Add(item = sel, proportion = 1,
-+ flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
-+ border = 5)
-+
-+ return selSizer
-+
-+ def OnClose(self, event):
-+ """!Close dialog
-+ """
-+ if not self.IsModal():
-+ self.Destroy()
-+ event.Skip()
-+
-+ def OnOk(self, event):
-+ """!
-+ """
-+ band_1 = self.band_1_ch.GetSelection()
-+ band_2 = self.band_2_ch.GetSelection()
-+
-+
-+ if band_1 == band_2:
-+ GError(_("Selected bands must be different."))
-+ return
-+
-+ #TODO axes selection
-+ if band_1 > band_2:
-+ tmp_band = band_2
-+ band_2 = band_1
-+ band_1 = band_2
-+
-+ self.scatt_id = BandsToidScatt(band_1, band_2, len(self.bands))
-+
-+ event.Skip()
-+
-+ def GetScattId(self):
-+ return self.scatt_id
-+
-+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)
-+
-+ def GetPlot(self):
-+ return self.scatt
-+
-+ def _doLayout(self):
-+ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
-+ self.main_sizer.Add(self.self)
-+
-+ self.panel.SetSizer(self.main_sizer)
-+ self.main_sizer.Fit(self)
-+
-+ def OnPlotClosed(self, scatt_id):
-+ self.Destroy()
-+
-+class CategoryListCtrl(wx.ListCtrl,
-+ listmix.ListCtrlAutoWidthMixin,
-+ listmix.TextEditMixin):
-+
-+ def __init__(self, parent, cats_mgr, id = wx.ID_ANY):
-+
-+ wx.ListCtrl.__init__(self, parent, id,
-+ style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES)
-+ self.columns = ((_('Category name'), 'name'),
-+ (_('Color'), 'color'))
-+ self.Populate(columns = self.columns)
-+
-+ self.cats_mgr = cats_mgr
-+ self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+
-+ self.rightClickedItemIdx = wx.NOT_FOUND
-+
-+ listmix.ListCtrlAutoWidthMixin.__init__(self)
-+
-+ listmix.TextEditMixin.__init__(self)
-+
-+ self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnEdit)
-+ self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSel)
-+
-+ self.cats_mgr.setCategoryAttrs.connect(self.Update)
-+ self.cats_mgr.deletedCategory.connect(self.Update)
-+ self.cats_mgr.addedCategory.connect(self.Update)
-+
-+ def Update(self, **kwargs):
-+ self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+ self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
-+
-+ def InitCoreCats(self):
-+ self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+ self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
-+
-+ def SetVirtualData(self, row, column, text):
-+ attr = self.columns[column][1]
-+ if attr == 'name':
-+ try:
-+ text.encode('ascii')
-+ except UnicodeEncodeError:
-+ GMessage(parent = self, message = _("Please use only ASCII characters."))
-+ return
-+
-+ cat_id = self.cats_mgr.GetCategories()[row]
-+
-+ self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
-+ self.cats_mgr.SetCategoryAttrs(cat_id, {attr : text})
-+ self.cats_mgr.setCategoryAttrs.connect(self.Update)
-+
-+ self.Select(row)
-+
-+ def Populate(self, columns):
-+ for i, col in enumerate(columns):
-+ self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
-+
-+ self.SetColumnWidth(0, 100)
-+ self.SetColumnWidth(1, 100)
-+
-+ def AddCategory(self):
-+
-+ self.cats_mgr.addedCategory.disconnect(self.Update)
-+ cat_id = self.cats_mgr.AddCategory()
-+ self.cats_mgr.addedCategory.connect(self.Update)
-+
-+ if cat_id < 0:
-+ GError(_("Maximum limit of categories number was reached."))
-+ return
-+ self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+
-+ def DeleteCategory(self):
-+ indexList = sorted(self.GetSelectedIndices(), reverse = True)
-+ cats = []
-+ for i in indexList:
-+ # remove temporary raster
-+ cat_id = self.cats_mgr.GetCategories()[i]
-+
-+ cats.append(cat_id)
-+
-+ self.cats_mgr.deletedCategory.disconnect(self.Update)
-+ self.cats_mgr.DeleteCategory(cat_id)
-+ self.cats_mgr.deletedCategory.connect(self.Update)
-+
-+ self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+
-+ def OnSel(self, event):
-+ self.cats_mgr.SetSelectedCat(event.GetIndex() + 1)
-+
-+ event.Skip()
-+
-+ def GetSelectedIndices(self, state = wx.LIST_STATE_SELECTED):
-+ indices = []
-+ lastFound = -1
-+ while True:
-+ index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state)
-+ if index == -1:
-+ break
-+ else:
-+ lastFound = index
-+ indices.append(index)
-+ return indices
-+
-+ def OnEdit(self, event):
-+ currentItem = event.m_itemIndex
-+ currentCol = event.m_col
-+
-+ if currentCol == 1:
-+ dlg = wx.ColourDialog(self)
-+ dlg.GetColourData().SetChooseFull(True)
-+
-+ if dlg.ShowModal() == wx.ID_OK:
-+ color = dlg.GetColourData().GetColour().Get()
-+ color = ':'.join(map(str, color))
-+ self.SetVirtualData(currentItem, currentCol, color)
-+ dlg.Destroy()
-+ wx.CallAfter(self.SetFocus)
-+
-+ event.Skip()
-+
-+
-+ def DeselectAll(self):
-+ """!Deselect all items"""
-+ indexList = self.GetSelectedIndices()
-+ for i in indexList:
-+ self.Select(i, on = 0)
-+
-+ # no highlight
-+ self.OnCategorySelected(None)
-+
-+ def OnGetItemText(self, item, col):
-+ attr = self.columns[col][1]
-+ cat_id = self.cats_mgr.GetCategories()[item]
-+
-+ return self.cats_mgr.GetCategoryAttrs(cat_id)[attr]
-+
-+ def OnGetItemImage(self, item):
-+ return -1
-+
-+ def OnGetItemAttr(self, item):
-+ return None
-Index: gui/wxpython/scatt_plot/toolbars.py
-===================================================================
---- gui/wxpython/scatt_plot/toolbars.py (revision 0)
-+++ gui/wxpython/scatt_plot/toolbars.py (working copy)
-@@ -0,0 +1,106 @@
-+"""!
-+ at package scatt_plot.toolbars
-+
-+ at brief Scatter plot - toolbars
-+
-+Classes:
-+ - toolbars::MainToolbar
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+
-+
-+import wx
-+
-+from icons.icon import MetaIcon
-+from gui_core.toolbars import BaseToolbar, BaseIcons
-+from core.gcmd import RunCommand
-+
-+class MainToolbar(BaseToolbar):
-+ """!Main toolbar
-+ """
-+ def __init__(self, parent):
-+ BaseToolbar.__init__(self, parent)
-+
-+ self.InitToolbar(self._toolbarData())
-+
-+ # realize the toolbar
-+ self.Realize()
-+
-+ def _toolbarData(self):
-+
-+ icons = {
-+ 'set_data' : MetaIcon(img = 'layer-raster-add',
-+ label = _('Set input raster data for plots')),
-+ 'settings' : BaseIcons['settings'].SetLabel( _('Ssettings')),
-+ 'help' : MetaIcon(img = 'help',
-+ label = _('Show manual')),
-+ 'add_scatt_pl' : MetaIcon(img = 'layer-raster-analyze',
-+ label = _('Add scatter plot'))
-+ }
-+
-+ return self._getToolbarData((
-+ ('sat_data', icons["set_data"],
-+ self.parent.OnSetData),
-+ (None, ),
-+ ('add_scatt', icons["add_scatt_pl"],
-+ self.parent.OnAddScattPl),
-+ #('settings', icons["settings"],
-+ # self.parent.OnSettings),
-+ #('help', icons["help"],
-+ # self.OnHelp),
-+ ("quit", BaseIcons['quit'],
-+ self.parent.OnCloseDialog)
-+ ))
-+
-+ def OnHelp(self, event) :
-+ RunCommand('g.manual',
-+ entry = 'wxGUI.scatt_plot')
-+
-+class CategoriesToolbar(BaseToolbar):
-+
-+ def __init__(self, parent, cats_list, scatts_dlg):
-+ BaseToolbar.__init__(self, parent)
-+ self.cats_list = cats_list
-+ self.scatts_dlg = scatts_dlg
-+
-+ self.InitToolbar(self._toolbarData())
-+
-+
-+ # realize the toolbar
-+ self.Realize()
-+
-+
-+ def _toolbarData(self):
-+
-+ icons = {
-+ 'editCatAdd' : MetaIcon(img = 'polygon-create',
-+ label = _('Add region to category mode')),
-+ 'editCatRemove' : MetaIcon(img = 'polygon-delete',
-+ label = _('Remove region to category mode')),
-+ 'addCat' : MetaIcon(img = 'layer-add',
-+ label = _('Add category')),
-+ 'deleteCat' : MetaIcon(img = 'layer-remove',
-+ label = _('Delete category'))
-+ }
-+
-+ return self._getToolbarData((('editCatAdd', icons['editCatAdd'],
-+ lambda event: self.scatts_dlg.EditCatAdd(),
-+ wx.ITEM_CHECK),
-+ ('editCatRemove', icons['editCatRemove'],
-+ lambda event: self.scatts_dlg.EditCatRemove(),
-+ wx.ITEM_CHECK),
-+ (None, ),
-+ ('addCat', icons["addCat"],
-+ lambda event: self.cats_list.AddCategory()),
-+ ('deleteCat', icons["deleteCat"],
-+ lambda event: self.cats_list.DeleteCategory())))
-+
-+ def GetToolId(self, toolName): #TODO can be useful in base
-+
-+ return vars(self)[toolName]
-\ No newline at end of file
-Index: gui/wxpython/scatt_plot/core_c.py
-===================================================================
---- gui/wxpython/scatt_plot/core_c.py (revision 0)
-+++ gui/wxpython/scatt_plot/core_c.py (working copy)
-@@ -0,0 +1,211 @@
-+"""!
-+ at package scatt_plot.scatt_plot
-+
-+ at brief Functions which work with scatter plot c code.
-+
-+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)
-+"""
-+
-+from multiprocessing import Process, Queue
-+
-+from ctypes import *
-+try:
-+ from grass.lib.imagery import *
-+ from grass.lib.gis import Cell_head, G_get_window
-+
-+except ImportError, e:
-+ sys.stderr.write(_("Loading imagery lib failed"))
-+
-+def ComputeScatts(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out):
-+
-+ #return _computeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out)
-+
-+ # Queue object for interprocess communication
-+ q = Queue()
-+
-+ # The separate render process
-+ p = Process(target=_computeScattsProcess, args=(region, scatt_conds, bands,
-+ n_bands, scatts, cats_rasts_in, cats_rasts_out, q))
-+ p.start()
-+ ret = q.get()
-+ p.join()
-+
-+ return ret[0], ret[1]
-+
-+def UpdateCatRast(patch_rast, region, cat_rast):
-+
-+ #return ComputeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts)
-+ # Queue object for interprocess communication
-+
-+ #_updateCatRastProcess(patch_rast, region, cat_rast, None)
-+ #return
-+ q = Queue()
-+ # The separate render process
-+ p = Process(target=_updateCatRastProcess, args=(patch_rast, region, cat_rast, q))
-+ p.start()
-+ #ret = q.get()
-+ p.join()
-+
-+ #return ret[0], ret[1]
-+
-+def CreateCatRast(region, cat_rast):
-+
-+ cell_head = _regionToCellHead(region)
-+ I_create_cat_rast(pointer(cell_head), cat_rast)
-+
-+def _computeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out, output_queue):
-+
-+ #TODO names for types not 0 and 1?
-+ sccats_c, vals_dt = _getComputationStruct(scatts, 0, n_bands)
-+ scatt_conds_c, vals_dt2 = _getComputationStruct(scatt_conds, 1, n_bands)
-+
-+ char_bands = _stringListToCharArr(bands)
-+ char_cats_rasts_out = _stringListToCharArr(cats_rasts_out)
-+ char_cats_rasts_in = _stringListToCharArr(cats_rasts_in)
-+
-+ cell_head = _regionToCellHead(region)
-+
-+ ret = I_compute_scatts(pointer(cell_head),
-+ pointer(scatt_conds_c),
-+ pointer(char_bands),
-+ n_bands,
-+ pointer(sccats_c),
-+ pointer(char_cats_rasts_in),
-+ pointer(char_cats_rasts_out))
-+
-+ I_sc_free_cats(pointer(sccats_c))
-+ I_sc_free_cats(pointer(scatt_conds_c))
-+
-+ output_queue.put((ret, scatts))
-+ #return (ret, scatts)
-+
-+def _regionToCellHead(region):
-+ cell_head = struct_Cell_head()
-+ G_get_window(pointer(cell_head))
-+
-+ convert_dict = {'n' : 'north', 'e' : 'east',
-+ 'w' : 'west', 's' : 'south',
-+ 'nsres' : 'ns_res',
-+ 'ewres' : 'ew_res'}
-+
-+ for k, v in region.iteritems():
-+ if k in ["rows", "cols", "cells"]:
-+ v = int(v)
-+ else:
-+ v = float(v)
-+
-+ if convert_dict.has_key(k):
-+ k = convert_dict[k]
-+
-+ setattr(cell_head, k, v)
-+
-+ return cell_head
-+
-+def _stringListToCharArr(str_list):
-+
-+ arr = c_char_p * len(str_list)
-+ char_arr = arr()
-+ for i, st in enumerate(str_list):
-+ if st:
-+ char_arr[i] = st
-+ else:
-+ char_arr[i] = None
-+
-+ return char_arr
-+
-+def _getComputationStruct(cats, cats_type, n_bands):
-+
-+ sccats = struct_scCats()
-+ I_sc_init_cats(pointer(sccats), c_int(n_bands), c_int(cats_type));
-+
-+ #for i in range(sccats.n_a_cats):
-+ # cat_id = sccats.cats_ids[i]
-+ # I_sc_delete_cat(pointer(sccats), cat_id)
-+ # i -= 1
-+
-+ vals_dt = []
-+ for cat_id, scatt_ids in cats.iteritems():
-+ I_sc_add_cat(pointer(sccats), cat_id)
-+
-+ for scatt_id, dt in scatt_ids.iteritems():
-+ # if key is missing condition is always True (full scatter plor is computed)
-+ if cats[cat_id].has_key(scatt_id):
-+
-+ vals = dt["np_vals"]
-+ #TODO hack
-+ vals.shape = (256 * 256)
-+
-+ c_uint_p = ctypes.POINTER(ctypes.c_uint)
-+ scatt_vals = scdScattData()
-+ if cats_type == 0:
-+ vals[:] = 0
-+ scatt_vals.scatt_vals_arr = vals.ctypes.data_as(c_uint_p)
-+
-+ else:
-+ #TODO solve proble with short integer
-+ scatt_vals.b_conds_arr = vals.ctypes.data_as(c_uint_p)
-+
-+ vals_dt.append(scatt_vals)
-+
-+ #vals_dt.append(data_p)
-+ vals.shape = (256, 256)
-+ I_sc_insert_scatt_data(pointer(sccats),
-+ pointer(scatt_vals),
-+ cat_id, scatt_id)
-+
-+ return sccats, vals_dt
-+
-+def _updateCatRastProcess(patch_rast, region, cat_rast, output_queue):
-+
-+ #TODO names for types not 0 and 1?
-+
-+ cell_head = _regionToCellHead(region)
-+
-+
-+ cat_rast
-+ I_insert_patch_to_cat_rast(patch_rast,
-+ pointer(cell_head),
-+ cat_rast)
-+
-+ #print re
-+ #output_queue.put((ret, scatts))
-+ #return (ret, scatts)
-+
-+"""
-+class A:
-+ def __init__(self):
-+ self.i = 0
-+
-+ def incr(self):
-+ self.i += 1
-+ return self.i
-+
-+def worker(input, output):
-+ print "ahoj"
-+ for func, args in iter(input.get, 'STOP'):
-+ print "jedu"
-+ result = func.incr
-+ output.put(result)
-+
-+def test():
-+ # Create queues
-+ task_queue = Queue()
-+ done_queue = Queue()
-+
-+ # Start worker processes
-+ a = A()
-+
-+ prc = Process(target=worker, args=(task_queue, done_queue)).start()
-+ task_queue.put((a,1))
-+
-+ data = done_queue.get()
-+ print data
-+ task_queue.put('STOP')
-+"""
-Index: gui/wxpython/scatt_plot/__init__.py
-===================================================================
---- gui/wxpython/scatt_plot/__init__.py (revision 0)
-+++ gui/wxpython/scatt_plot/__init__.py (working copy)
-@@ -0,0 +1,8 @@
-+all = [
-+ 'dialogs',
-+ 'gthreading',
-+ 'plots',
-+ 'sc_pl_core',
-+ 'toolbars',
-+ 'core_c',
-+ ]
-Index: gui/wxpython/scatt_plot/plots.py
-===================================================================
---- gui/wxpython/scatt_plot/plots.py (revision 0)
-+++ gui/wxpython/scatt_plot/plots.py (working copy)
-@@ -0,0 +1,185 @@
-+"""!
-+ at package scatt_plot.dialogs
-+
-+ at brief Ploting widgets.
-+
-+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 wx
-+import numpy as np
-+import random
-+try:
-+ haveMatPlot = True
-+ import matplotlib
-+ matplotlib.use('WXAgg')
-+ from matplotlib.figure import Figure
-+ from matplotlib.backends.backend_wxagg import \
-+ FigureCanvasWxAgg as FigCanvas, \
-+ NavigationToolbar2WxAgg as NavigationToolbar
-+except ImportError:
-+ haveMatPlot = False
-+
-+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
-+
-+ self._createWidgets()
-+ self._doLayout()
-+ self.scatt_id = scatt_id
-+ self.scatt_mgr = scatt_mgr
-+ self.press_coords = None
-+
-+ self.cidpress = None
-+ self.cidrelease = None
-+
-+ def StartCategoryEdit(self):
-+ 'connect to all the events we need'
-+ self.cidpress = self.canvas.mpl_connect(
-+ 'button_press_event', self.OnPress)
-+ self.cidrelease = self.canvas.mpl_connect(
-+ 'button_release_event', self.OnRelease)
-+ #self.cidmotion = self.canvas.mpl_connect(
-+ # 'motion_notify_event', self.OnRelease)
-+
-+ def OnPress(self, event):
-+ 'on button press we will see if the mouse is over us and store some data'
-+
-+ if event.xdata and event.ydata:
-+ self.press_coords = { 'x' : event.xdata, 'y' : event.ydata}
-+ else:
-+ self.press_coords = None
-+
-+ def OnRelease(self, event):
-+ 'on release we reset the press data'
-+
-+ if event.xdata and event.ydata and self.press_coords:
-+
-+ bbox = {}
-+ if event.ydata > self.press_coords['y']:
-+ bbox['up_y'] = event.ydata
-+ bbox['btm_y'] = self.press_coords['y']
-+ else:
-+ bbox['up_y'] = self.press_coords['y']
-+ bbox['btm_y'] = event.ydata
-+
-+ if event.xdata > self.press_coords['x']:
-+ bbox['up_x'] = event.xdata
-+ bbox['btm_x'] = self.press_coords['x']
-+ else:
-+ bbox['up_x'] = self.press_coords['x']
-+ bbox['btm_x'] = event.xdata
-+
-+ self.scatt_mgr.SetEditCatData(self.scatt_id, bbox)
-+
-+ def StopCategoryEdit(self):
-+ 'disconnect all the stored connection ids'
-+
-+ if self.cidpress:
-+ self.canvas.mpl_disconnect(self.cidpress)
-+ if self.cidrelease:
-+ self.canvas.mpl_disconnect(self.cidrelease)
-+ #self.canvas.mpl_disconnect(self.cidmotion)
-+
-+ def _createWidgets(self):
-+
-+ # Create the mpl Figure and FigCanvas objects.
-+ # 5x4 inches, 100 dots-per-inch
-+ #
-+ self.dpi = 100
-+ self.fig = Figure((5.0, 4.0), dpi=self.dpi)
-+ self.canvas = FigCanvas(self, -1, self.fig)
-+
-+ # Since we have only one plot, we can use add_axes
-+ # instead of add_subplot, but then the subplot
-+ # configuration tool in the navigation toolbar wouldn't
-+ # work.
-+ #
-+ self.axes = self.fig.add_subplot(111)
-+
-+ # Bind the 'pick' event for clicking on one of the bars
-+ #
-+ self.canvas.mpl_connect('button_press_event', self.on_pick)
-+
-+
-+ # Create the navigation toolbar, tied to the canvas
-+ #
-+ self.toolbar = NavigationToolbar(self.canvas)
-+
-+ 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.SetSizer(self.main_sizer)
-+ self.main_sizer.Fit(self)
-+
-+ def Plot(self, scatts, styles):
-+ """ Redraws the figure
-+ """
-+
-+ self.axes.clear()
-+ for cat_id, cat in scatts.iteritems():
-+ if cat_id == 0:
-+ cmap = matplotlib.cm.jet
-+ cmap.set_bad('w',1.)
-+ cmap._init()
-+ cmap._lut[len(cmap._lut) - 1, -1] = 0
-+ else:
-+ colors = styles[cat_id]['color'].split(":")
-+
-+ cmap = matplotlib.cm.jet
-+ cmap.set_bad('w',1.)
-+ cmap._init()
-+ cmap._lut[len(cmap._lut) - 1, -1] = 0
-+ cmap._lut[:, 0] = int(colors[0])/255.0
-+ cmap._lut[:, 1] = int(colors[1])/255.0
-+ cmap._lut[:, 2] = int(colors[2])/255.0
-+
-+ masked_cat = np.ma.masked_less_equal(cat, 0)
-+
-+ self.axes.imshow(masked_cat, cmap = cmap, interpolation='nearest')
-+
-+ self.canvas.draw()
-+
-+ def on_pick(self, event):
-+ pass
-+ # The event received here is of the type
-+ # matplotlib.backend_bases.PickEvent
-+ #
-+ # It carries lots of information, of which we're using
-+ # only a small amount here.
-+ #
-+ #box_points = event.x
-+
-+ #msg = "You've clicked on a bar with coords:\n"
-+
-+ #dlg = wx.MessageDialog(
-+ # self,
-+ # msg,
-+ # "Click!",
-+ # wx.OK | wx.ICON_INFORMATION)
-+
-+ #dlg.ShowModal()
-+ #dlg.Destroy()
-+
-+ def on_exit(self, event):
-+
-+ self.CleanUp()
-+
-+ def CleanUp(self):
-+
-+ self.parent.OnPlotClosed(self.scatt_id)
-+ self.Destroy()
-\ No newline at end of file
-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,513 @@
-+"""!
-+ 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, BandsToidScatt
-+
-+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
-+
-+ wx.EvtHandler.__init__(self)
-+ self.giface = giface
-+ self.mapDisp = giface.GetMapDisplay()
-+ self.mapWin = giface.GetMapWindow()
-+
-+ 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)
-+ else:
-+ self.mapWin_conn = None
-+ self.iclass_conn = None
-+
-+ self.tasks_pids = {
-+ 'add_scatt' : -1,
-+ 'set_data' : -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
-+ self.tasks_pids['set_data'] = self.thread.GetId()
-+ self.thread.Run(callable = self.core.SetData, bands = bands)
-+
-+ def SetDataDone(self, event):
-+ self.data_set = True
-+ self.cats_mgr.InitCoreCats()
-+
-+ def OnOutput(self, event):
-+ """!Print thread output according to debug level.
-+ """
-+ print event.text
-+
-+ def GetBands(self):
-+ return self.core.GetBands()
-+
-+ def AddScattPlot(self, scatt_id):
-+
-+ self.tasks_pids['add_scatt'] = 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)
-+
-+ 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.ComputeCatScatts,
-+ 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 self.tasks_pids['add_scatt'] == event.pid:
-+ self.AddScattPlotDone(event)
-+ 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 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/vdigit/wxdigit.py
-===================================================================
---- gui/wxpython/vdigit/wxdigit.py (revision 57285)
-+++ gui/wxpython/vdigit/wxdigit.py (working copy)
-@@ -17,7 +17,7 @@
- (and NumPy would be an excellent candidate for acceleration via
- e.g. OpenCL or CUDA; I'm surprised it hasn't happened already).
-
--(C) 2007-2011 by the GRASS Development Team
-+(C) 2007-2011, 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.
-@@ -27,6 +27,8 @@
-
- import grass.script.core as grass
-
-+from grass.pydispatch.signal import Signal
-+
- from core.gcmd import GError
- from core.debug import Debug
- from core.settings import UserSettings
-@@ -176,7 +178,17 @@
-
- if self.poMapInfo:
- self.InitCats()
--
-+
-+ #TODO signal for errors?
-+ self.featureAdded = Signal('IVDigit.featureAdded')
-+ self.areasDeleted = Signal('IVDigit.areasDeleted')
-+ self.vertexMoved = Signal('IVDigit.vertexMoved')
-+ self.vertexAdded = Signal('IVDigit.vertexAdded')
-+ self.vertexRemoved = Signal('IVDigit.vertexRemoved')
-+ self.featuresDeleted = Signal('IVDigit.featuresDeleted')
-+ self.featuresMoved = Signal('IVDigit.featuresMoved')
-+ self.lineEdited = Signal('IVDigit.lineEdited')
-+
- def __del__(self):
- Debug.msg(1, "IVDigit.__del__()")
- Vect_destroy_line_struct(self.poPoints)
-@@ -394,7 +406,6 @@
-
- @return tuple (number of added features, feature ids)
- """
--
- layer = self._getNewFeaturesLayer()
- cat = self._getNewFeaturesCat()
-
-@@ -419,10 +430,14 @@
- return (-1, None)
-
- self.toolbar.EnableUndo()
--
-- return self._addFeature(vtype, points, layer, cat,
-- self._getSnapMode(), self._display.GetThreshold())
--
-+
-+ 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]})
-+
-+ return ret
-+
- def DeleteSelectedLines(self):
- """!Delete selected features
-
-@@ -434,16 +449,25 @@
- # colect categories for delete if requested
- deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
- catDict = dict()
-+
-+ old_geoms = []
-+ old_areas_cats = []
- if deleteRec:
- for i in self._display.selected['ids']:
-+
- 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))
-+
- cats = self.poCats.contents
-- for j in range(cats.n_cats):
-- if cats.field[j] not in catDict.keys():
-- catDict[cats.field[j]] = list()
-- catDict[cats.field[j]].append(cats.cat[j])
-+
-+ # catDict was not used -> put into comment
-+ #for j in range(cats.n_cats):
-+ # if cats.field[j] not in catDict.keys():
-+ # catDict[cats.field[j]] = list()
-+ # catDict[cats.field[j]].append(cats.cat[j])
-
- poList = self._display.GetSelectedIList()
- nlines = Vedit_delete_lines(self.poMapInfo, poList)
-@@ -456,7 +480,8 @@
- self._deleteRecords(cats)
- self._addChangeset()
- self.toolbar.EnableUndo()
--
-+ self.featuresDeleted.emit(old_geoms = old_geoms, old_areas_cats = old_areas_cats)
-+
- return nlines
-
- def _deleteRecords(self, cats):
-@@ -512,22 +537,123 @@
-
- @return number of deleted
- """
-+ if len(self._display.selected['ids']) < 1:
-+ return 0
-+
- poList = self._display.GetSelectedIList()
- cList = poList.contents
-
- nareas = 0
-+ old_geoms = []
-+ old_areas_cats = []
-+
- for i in range(cList.n_values):
-+
- if Vect_get_line_type(self.poMapInfo, cList.value[i]) != GV_CENTROID:
- continue
--
-+
-+ area = Vect_get_centroid_area(self.poMapInfo, cList.value[i]);
-+ if area > 0:
-+ geoms, cats = self._getaAreaGeomsCats(area)
-+ old_geoms += geoms
-+ old_areas_cats += cats
-+
- nareas += Vedit_delete_area_centroid(self.poMapInfo, cList.value[i])
-
- if nareas > 0:
- self._addChangeset()
- self.toolbar.EnableUndo()
-+ self.areasDeleted.emit(old_geoms = old_geoms, old_areas_cats = old_areas_cats)
-+
-+ return nareas
-+
-+
-+ def _getaAreaGeomsCats(self, area):
-+
-+ po_b_list = Vect_new_list()
-+ Vect_get_area_boundaries(self.poMapInfo, area, po_b_list);
-+ b_list = po_b_list.contents
-+
-+ geoms = []
-+ areas_cats = []
-+
-+ if b_list.n_values > 0:
-+ for i_line in range(b_list.n_values):
-+
-+ line = b_list.value[i_line];
-+
-+ geoms.append(self._getGeom(abs(line)))
-+ areas_cats.append(self._getLineAreasCategories(abs(line)))
-
-- return nareas
-+ Vect_destroy_list(po_b_list);
-+
-+ return geoms, areas_cats
-+
-+ def _getLineAreasCategories(self, ln_id):
-+
-+ ltype = Vect_read_line(self.poMapInfo, None, None, ln_id)
-+ if ltype != GV_BOUNDARY:
-+ return []
-+
-+ cats = [None, None]
-+
-+ left = c_int()
-+ right = c_int()
-+
-+ if Vect_get_line_areas(self.poMapInfo, ln_id, pointer(left), pointer(right)) == 1:
-+ areas = [left.value, right.value]
-+
-+ for i, a in enumerate(areas):
-+ if a > 0:
-+ centroid = Vect_get_area_centroid(self.poMapInfo, a)
-+ if centroid <= 0:
-+ continue
-+ c = self._getCategories(centroid)
-+ if c:
-+ cats[i] = c
-+
-+ return cats
-+
-+ def _getCategories(self, ln_id):
-+
-+ poCats = Vect_new_cats_struct()
-+ if Vect_read_line(self.poMapInfo, None, poCats, ln_id) < 0:
-+ Vect_destroy_cats_struct(poCats)
-+ return None
-+
-+ cCats = poCats.contents
-+
-+ cats = {}
-+ for j in range(cCats.n_cats):
-+ if cats.has_key(cCats.field[j]):
-+ cats[cCats.field[j]].append(cCats.cat[j])
-+ else:
-+ cats[cCats.field[j]] = [cCats.cat[j]]
-
-+ Vect_destroy_cats_struct(poCats)
-+ return cats
-+
-+ def _getGeom(self, ln_id):
-+
-+ poPoints = Vect_new_line_struct()
-+ if Vect_read_line(self.poMapInfo, poPoints, None, ln_id) < 0:
-+ Vect_destroy_line_struct(poPoints)
-+ return None
-+
-+ geom = self._convertGeom(poPoints)
-+ Vect_destroy_line_struct(poPoints)
-+ return geom
-+
-+ def _convertGeom(self, poPoints):
-+
-+ Points = poPoints.contents
-+
-+ pts_geom = []
-+ for j in range(Points.n_points):
-+ pts_geom.append((Points.x[j], Points.y[j]))
-+
-+ return pts_geom
-+
- def MoveSelectedLines(self, move):
- """!Move selected features
-
-@@ -536,16 +662,39 @@
- if not self._checkMap():
- return -1
-
-+ nsel = len(self._display.selected['ids'])
-+ if nsel < 1:
-+ return -1
-+
- thresh = self._display.GetThreshold()
- snap = self._getSnapMode()
-
- poList = self._display.GetSelectedIList()
-+
-+ old_geoms = []
-+ 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()
- 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)
-+
- Vect_destroy_list(poList)
-
-+ cList = poNewIds.contents
-+
-+ if nlines > 0:
-+ new_areas_cats = []
-+ for i in range(cList.n_values):
-+ new_id = cList.value[i]
-+ new_areas_cats.append(self._getLineAreasCategories(new_id))
-+
-+ 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 @@
- if nlines > 0:
- self._addChangeset()
- self.toolbar.EnableUndo()
--
-+
-+ self.featuresMoved.emit(move = move,
-+ old_geoms = old_geoms,
-+ old_areas_cats = old_areas_cats,
-+ new_areas_cats = new_areas_cats)
- return nlines
-
- def MoveSelectedVertex(self, point, move):
-@@ -571,20 +724,33 @@
-
- if len(self._display.selected['ids']) != 1:
- return -1
--
-+
-+ # move only first found vertex in bbox
-+ poList = self._display.GetSelectedIList()
-+
-+ cList = poList.contents
-+ old_geom = self._getGeom(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)
--
-- # move only first found vertex in bbox
-- poList = self._display.GetSelectedIList()
-+
-+ poNewIds = Vect_new_list()
- 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(),
- move[0], move[1], 0.0,
-- 1, self._getSnapMode())
-+ 1, self._getSnapMode(), poNewIds)
- Vect_destroy_list(poList)
--
-+
-+ new_id = poNewIds.contents.value[0]
-+ Vect_destroy_list(poNewIds)
-+
-+ if new_id > -1:
-+ new_geom = self._getGeom(new_id)
-+ new_areas_cats = self._getLineAreasCategories(new_id)
-+
- if moved > 0 and self._settings['breakLines']:
- self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
- None)
-@@ -592,7 +758,13 @@
- if moved > 0:
- self._addChangeset()
- self.toolbar.EnableUndo()
--
-+
-+ if new_id > -1:
-+ self.vertexMoved.emit(new_geom = new_geom,
-+ new_areas_cats = new_areas_cats,
-+ old_areas_cats = old_areas_cats,
-+ old_geom = old_geom)
-+
- return moved
-
- def AddVertex(self, coords):
-@@ -681,6 +853,9 @@
- self._error.ReadLine(line)
- return -1
-
-+ old_geom = self._getGeom(line)
-+ old_areas_cats = self._getLineAreasCategories(line)
-+
- # build feature geometry
- Vect_reset_line(self.poPoints)
- for p in coords:
-@@ -703,7 +878,15 @@
- 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,
-+ old_areas_cats = old_areas_cats,
-+ new_geom = new_geom,
-+ new_areas_cats = new_areas_cats)
-+
- return newline
-
- def FlipLine(self):
-@@ -1510,26 +1693,49 @@
- return 0
-
- poList = self._display.GetSelectedIList()
-+ cList = poList.contents
-+
-+ old_geom = self._getGeom(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()
-+
- if add:
- ret = Vedit_add_vertex(self.poMapInfo, poList,
-- self.poPoints, thresh)
-+ self.poPoints, thresh, poNewIds)
- else:
- ret = Vedit_remove_vertex(self.poMapInfo, poList,
-- self.poPoints, thresh)
-+ self.poPoints, thresh, poNewIds)
-+
-+ 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 not add and ret > 0 and self._settings['breakLines']:
- self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
- None)
--
-+
- if ret > 0:
- self._addChangeset()
--
-+
-+ if new_id > -1:
-+ if add:
-+ self.vertexAdded.emit(old_geom = old_geom, new_geom = new_geom)
-+ else:
-+ self.vertexRemoved.emit(old_geom = old_geom,
-+ new_geom = new_geom,
-+ old_areas_cats = old_areas_cats,
-+ new_areas_cats = new_areas_cats)
-+
- return 1
-
- def GetLineCats(self, line):
-Index: gui/wxpython/vdigit/toolbars.py
-===================================================================
---- gui/wxpython/vdigit/toolbars.py (revision 57285)
-+++ 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)
-@@ -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
-===================================================================
---- gui/wxpython/Makefile (revision 57285)
-+++ 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)
-
-Index: gui/wxpython/mapdisp/toolbars.py
-===================================================================
---- gui/wxpython/mapdisp/toolbars.py (revision 57285)
-+++ 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 57285)
-+++ 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
-+ """
-+ if self.dialogs['scatt_plot']:
-+ self.dialogs['scatt_plot'].Raise()
-+ return
-+
-+ from scatt_plot.dialogs import ScattPlotMainDialog
-+ self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface)
-+
-+ self.dialogs['scatt_plot'].CenterOnScreen()
-+ self.dialogs['scatt_plot'].Show()
-+
- def OnVNet(self, event):
- """!Dialog for v.net* modules
- """
-Index: lib/vector/vedit/move.c
-===================================================================
---- lib/vector/vedit/move.c (revision 57285)
-+++ 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 57285)
-+++ 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 */
-Index: lib/imagery/scatt_sccats.c
-===================================================================
---- lib/imagery/scatt_sccats.c (revision 0)
-+++ lib/imagery/scatt_sccats.c (working copy)
-@@ -0,0 +1,321 @@
-+/*!
-+ \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_vals, 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_vals->b_conds_arr && cats->type == 1)
-+ return -1;
-+
-+ if(!scatt_vals->scatt_vals_arr && cats->type == 0)
-+ 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_vals;
-+ ++scatts->n_a_scatts;
-+
-+ return 0;
-+}
-+
-+int I_sc_remove_scatt_data(struct scCats * cats, struct scdScattData * scatt_vals, 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_vals = 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_vals = 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_vals, int n_vals, int type)
-+{
-+ scatt_vals->n_vals = n_vals;
-+
-+ if(type == 0)
-+ {
-+ scatt_vals->scatt_vals_arr = (unsigned int *) malloc(n_vals * sizeof(unsigned int));
-+ memset(scatt_vals->scatt_vals_arr, 0, n_vals * sizeof(unsigned int));
-+ scatt_vals->b_conds_arr = NULL;
-+ }
-+ else if(type == 1)
-+ {
-+ scatt_vals->b_conds_arr = (unsigned short *) malloc(n_vals * sizeof(unsigned short));
-+ memset(scatt_vals->b_conds_arr, 0, n_vals * sizeof(unsigned short));
-+ scatt_vals->scatt_vals_arr = NULL;
-+ }
-+
-+ return;
-+}
-+
-+void I_scd_free_scatt_data(struct scdScattData * scatt_vals)
-+{
-+
-+ free(scatt_vals->b_conds_arr);
-+ free(scatt_vals->scatt_vals_arr);
-+
-+ scatt_vals = NULL;
-+
-+ return;
-+}
-+
-+int I_scd_get_data_size(struct scdScattData * scatt_vals)
-+{
-+ return scatt_vals->n_vals;
-+}
-+
-+void * I_scd_get_data_ptr(struct scdScattData * scatt_vals)
-+{
-+ if(!scatt_vals->b_conds_arr)
-+ return scatt_vals->b_conds_arr;
-+ else if(!scatt_vals->scatt_vals_arr)
-+ return scatt_vals->scatt_vals_arr;
-+
-+ return NULL;
-+}
-+
-+int I_scd_set_value(struct scdScattData * scatt_vals, unsigned int val_idx, unsigned int val)
-+{
-+ if(val_idx < 0 && val_idx > scatt_vals->n_vals)
-+ return -1;
-+
-+ if(scatt_vals->b_conds_arr)
-+ scatt_vals->b_conds_arr[val_idx] = val;
-+ else if(scatt_vals->scatt_vals_arr)
-+ scatt_vals->scatt_vals_arr[val_idx] = val;
-+ else
-+ return -1;
-+
-+ return 0;
-+}
-Index: lib/imagery/scatt.c
-===================================================================
---- lib/imagery/scatt.c (revision 0)
-+++ lib/imagery/scatt.c (working copy)
-@@ -0,0 +1,582 @@
-+/*!
-+ \file lib/imagery/scatt.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>
-+
-+
-+static const int CAT_RAST_SCATT_SEL = 2;
-+static const int CAT_RAST_RAST_SEL = 1;
-+static const int CAT_RAST_NULL = 0;
-+
-+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);
-+}
-+
-+int I_create_cat_rast(struct Cell_head * cat_rast_region, const char * cat_rast)
-+{
-+ FILE * f_cat_rast;
-+ char cat_rast_header[1024];//TODO magic number
-+ int i_row, i_col;
-+ int head_nchars;
-+
-+ unsigned char * row_data;
-+
-+ f_cat_rast = fopen(cat_rast, "wb");
-+ if(!f_cat_rast)
-+ return -1;
-+
-+ head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
-+
-+ fwrite(cat_rast_header, sizeof(char), head_nchars/sizeof(char), f_cat_rast);
-+ if (ferror(f_cat_rast)){
-+ fclose(f_cat_rast);
-+ return -1;
-+ }
-+
-+ row_data = (unsigned char *) G_malloc(cat_rast_region->cols * sizeof(unsigned char));
-+ for(i_col = 0; i_col < cat_rast_region->cols; i_col++)
-+ row_data[i_col] = 0 & 255;
-+
-+ 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);
-+ G_debug(3, "Unable to write into file.");
-+ return -1;
-+ }
-+ }
-+
-+ fclose(f_cat_rast);
-+ return 0;
-+}
-+
-+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,
-+ intersec->east, intersec->west, intersec->ns_res, intersec->ew_res);
-+}
-+
-+static int regions_intersecion(struct Cell_head * A, struct Cell_head * B, struct Cell_head * intersec)
-+{
-+
-+ if(B->north < A->south) return -1;
-+ else if(B->north > A->north) intersec->north = A->north;
-+ else intersec->north = B->north;
-+
-+ if(B->south > A->north) return -1;
-+ else if(B->south < A->south) intersec->south = A->south;
-+ else intersec->south = B->south;
-+
-+ if(B->east < A->west) return -1;
-+ else if(B->east > A->east) intersec->east = A->east;
-+ else intersec->east = B->east;
-+
-+ if(B->west > A->east) return -1;
-+ else if(B->west < A->west) intersec->west = A->west;
-+ else intersec->west = B->west;
-+
-+ if(intersec->north == intersec->south) return -1;
-+
-+ if(intersec->east == intersec->west) return -1;
-+
-+ return 0;
-+
-+}
-+
-+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)
-+ return -1;
-+
-+ if(A->ew_res != B->ew_res)
-+ return -1;
-+
-+ ns_res = A->ns_res;
-+ ew_res = A->ew_res;
-+
-+ if(regions_intersecion(A, B, &intersec) == -1)
-+ return -1;
-+
-+ A_bounds->north = ceil((A->north - intersec.north - ns_res * 0.5) / ns_res);
-+ A_bounds->south = ceil((A->north - intersec.south - ns_res * 0.5) / ns_res);
-+
-+ A_bounds->east = ceil((intersec.east - A->west - ew_res * 0.5) / ew_res);
-+ A_bounds->west = ceil((intersec.west - A->west - ew_res * 0.5) / ew_res);
-+
-+ B_bounds->north = ceil((B->north - intersec.north - ns_res * 0.5) / ns_res);
-+ B_bounds->south = ceil((B->north - intersec.south - ns_res * 0.5) / ns_res);
-+
-+ B_bounds->east = ceil((intersec.east - B->west - ew_res * 0.5) / ew_res);
-+ B_bounds->west = ceil((intersec.west - B->west - ew_res * 0.5) / ew_res);
-+
-+ return 0;
-+}
-+
-+
-+int I_insert_patch_to_cat_rast(const char * patch_rast, struct Cell_head * cat_rast_region, const char * cat_rast)
-+{
-+
-+ FILE * f_cat_rast;
-+ struct Cell_head patch_region, patch_bounds, cat_rast_bounds;
-+ char cat_rast_header[1024];//TODO magic number
-+ int i_row, i_col, ncols, nrows, cat_rast_col, patch_col, val;
-+ int head_nchars;
-+ int fd_patch_rast, init_shift, step_shift;
-+ unsigned char * patch_data;
-+
-+ char * null_chunk;
-+
-+ //TODO G_free mapset (aslo in compute scatts)
-+ const char *mapset;
-+
-+ struct Cell_head patch_lines, cat_rast_lines;
-+
-+ unsigned char * row_data;
-+
-+ f_cat_rast = fopen(cat_rast, "rb+");
-+ if(!f_cat_rast)
-+ return -10;
-+
-+
-+ /* 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;
-+ }
-+
-+ Rast_get_cellhd(patch_rast, mapset, &patch_region);
-+ Rast_set_window(&patch_region);
-+
-+ if ((fd_patch_rast = Rast_open_old(patch_rast, mapset)) < 0) {
-+ fclose(f_cat_rast);
-+ return -3;
-+ }
-+
-+ null_chunk = Rast_allocate_null_buf();
-+
-+ if(get_rows_and_cols_bounds(cat_rast_region, &patch_region, &cat_rast_bounds, &patch_bounds) == -1) return -1;
-+
-+ ncols = cat_rast_bounds.east - cat_rast_bounds.west;
-+ nrows = cat_rast_bounds.south - cat_rast_bounds.north;
-+
-+ patch_data = (unsigned char *) G_malloc(ncols * sizeof(unsigned char));
-+
-+ init_shift = head_nchars + cat_rast_region->cols * cat_rast_bounds.north + cat_rast_bounds.west;
-+
-+ if(fseek(f_cat_rast, init_shift, SEEK_SET) != 0) {
-+ G_message("seek failed");
-+ return -4;
-+ }
-+
-+ 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);
-+
-+ for(i_col = 0; i_col < ncols; i_col++) {
-+ patch_col = patch_bounds.west + i_col;
-+
-+ if(null_chunk[patch_col] != 1)
-+ patch_data[i_col] = 1 & 255;
-+ else {
-+ patch_data[i_col] = 0 & 255;
-+ }
-+ }
-+
-+ fwrite(patch_data, sizeof(unsigned char), (ncols)/sizeof(unsigned char), f_cat_rast);
-+ if (ferror(f_cat_rast))
-+ {
-+ G_free(null_chunk);
-+ fclose(f_cat_rast);
-+ return -5;
-+ }
-+ if(fseek(f_cat_rast, step_shift, SEEK_CUR) != 0) {
-+ G_message("seek failed");
-+ return -6;
-+ }
-+ }
-+
-+ Rast_close(fd_patch_rast);
-+ G_free(null_chunk);
-+ 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)
-+{
-+ int band_axis_1, band_axis_2, i_scatt, array_idx, cat_idx, i_chunks_pix;
-+ int r_bits = 256;
-+
-+ CELL * band_1_chunks;
-+ CELL * band_2_chunks;
-+ char * band_1_null_chunks,* band_2_null_chunks;
-+
-+ int * scatts_bands = scatts->scatts_bands;
-+ for(i_scatt = 0; i_scatt < scatts->n_a_scatts; i_scatt++)
-+ {
-+ band_1_chunks = chunks[scatts_bands[i_scatt * 2]];
-+ band_2_chunks = chunks[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]];
-+
-+ for(i_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
-+ {
-+ if(!belongs_pix[i_chunks_pix] ||
-+ band_1_null_chunks[i_chunks_pix] == 1 ||
-+ band_2_null_chunks[i_chunks_pix] == 1)
-+ continue;
-+
-+ array_idx = band_1_chunks[i_chunks_pix] + band_2_chunks[i_chunks_pix] * r_bits;
-+
-+ ++scatts->scatts_arr[i_scatt]->scatt_vals_arr[array_idx];
-+ }
-+ }
-+}
-+
-+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)
-+{
-+
-+ int i_chunks_pix, i_cat, i_scatt, n_a_scatts, i_cond;
-+ int cat_id, scatt_plts_cat_idx, array_idx;
-+ char * band_1_null_chunks,* band_2_null_chunks;
-+
-+ int r_bits = 256;
-+
-+ struct scScatts * scatts_conds;
-+ struct scScatts * scatt_plts_scatts;
-+ struct scdScattData * conds;
-+
-+ int * scatts_bands;
-+ struct scdScattData ** scatts_arr;
-+
-+ CELL * band_1_chunks;
-+ CELL * band_2_chunks;
-+ unsigned int * 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));
-+
-+ for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
-+ {
-+ scatts_conds = scatt_conds->cats_arr[i_cat];
-+
-+ cat_id = scatt_conds->cats_ids[i_cat];
-+
-+ scatt_plts_cat_idx = scatt_plts->cats_idxs[cat_id];
-+ if(scatt_plts_cat_idx < 0)
-+ continue;
-+
-+ scatt_plts_scatts = scatt_plts->cats_arr[scatt_plts_cat_idx];
-+
-+ G_zero(belongs_pix, chunk_size * sizeof(unsigned short));
-+
-+ if(!scatts_conds->n_a_scatts && !f_cats_rasts_in[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;
-+ }
-+ }
-+ else
-+ {
-+ scatts_bands = scatts_conds->scatts_bands;
-+
-+ if(f_cats_rasts_in[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]))
-+ {
-+ 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++)
-+ {
-+ if(rast_pixs[i_chunks_pix] != 0 & 255)
-+ belongs_pix[i_chunks_pix] = 1;
-+ }
-+
-+ // test every defined conditions in scatter plots
-+ for(i_scatt = 0; i_scatt < scatts_conds->n_a_scatts; i_scatt++)
-+ {
-+ band_1_chunks = chunks[scatts_bands[i_scatt * 2]];
-+ band_2_chunks = chunks[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]];
-+
-+ i_scatt_conds = scatts_conds->scatts_arr[i_scatt]->b_conds_arr;
-+
-+ for(i_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
-+ {
-+ if(belongs_pix[i_chunks_pix] ||
-+ band_1_null_chunks[i_chunks_pix] == 1 ||
-+ band_2_null_chunks[i_chunks_pix] == 1)
-+ continue;
-+
-+ if(i_scatt_conds[band_1_chunks[i_chunks_pix] + band_2_chunks[i_chunks_pix] * r_bits])
-+ belongs_pix[i_chunks_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;
-+
-+ 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;
-+ }
-+ }
-+
-+ update_cat_scatt_plt(chunks, null_chunks, chunk_size, belongs_pix, scatt_plts_scatts);
-+ }
-+
-+ G_free(rast_pixs);
-+ G_free(belongs_pix);
-+
-+ return 0;
-+}
-+
-+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
-+ int i_cat, i_scatt, cat_id;
-+
-+ for(i_cat = 0; i_cat < cats->n_a_cats; i_cat++)
-+ {
-+ for(i_scatt = 0; i_scatt < cats->cats_arr[i_cat]->n_a_scatts; i_scatt++)
-+ {
-+ G_debug(3, "Active scatt %d in catt %d", i_scatt, i_cat);
-+
-+ b_needed_bands[cats->cats_arr[i_cat]->scatts_bands[i_scatt * 2]] = 1;
-+ b_needed_bands[cats->cats_arr[i_cat]->scatts_bands[i_scatt * 2 + 1]] = 1;
-+ }
-+ }
-+ 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)
-+{
-+ int i, band_id;
-+
-+ for(i = 0; i < (* n_a_bands); i++)
-+ {
-+ 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]);
-+ }
-+ }
-+
-+ if(f_cats_rasts_in)
-+ for(i = 0; i < n_a_cats; i++)
-+ if(f_cats_rasts_in[i])
-+ fclose(f_cats_rasts_in[i]);
-+
-+ if(f_cats_rasts_out)
-+ for(i = 0; i < n_a_cats; i++)
-+ if(f_cats_rasts_out[i])
-+ fclose(f_cats_rasts_out[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)
-+{
-+ int i_cat, id_cat;
-+
-+ for(i_cat = 0; i_cat < n_a_cats; i_cat++)
-+ {
-+ 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;
-+ }
-+ else
-+ f_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)
-+{
-+ int i_cat, id_cat, head_nchars;
-+ char cat_rast_header[1024];//TODO magic number
-+
-+ head_nchars = get_cat_rast_header(region, cat_rast_header);
-+
-+ for(i_cat = 0; i_cat < n_a_cats; i_cat++)
-+ {
-+ if(!f_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;
-+ }
-+
-+ return head_nchars;
-+
-+}
-+
-+//TODO change name: I_UpdateScattData???
-+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 ||
-+ n_bands != scatt_conds->n_bands)
-+ return -1;
-+
-+ const char *mapset;
-+
-+ FILE * f_cats_rasts_out[scatt_conds->n_a_cats];
-+ FILE * f_cats_rasts_in[scatt_conds->n_a_cats];
-+
-+ CELL * chunks[n_bands];
-+ char * null_chunks[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;
-+ int fd_bands[n_bands];
-+ for(i_band = 0; i_band < n_bands; i_band++)
-+ fd_bands[i_band] = -1;
-+
-+ int bands_ids[n_bands];
-+ for(i_band = 0; i_band < n_bands; i_band++)
-+ bands_ids[i_band] = -1;
-+
-+ int b_needed_bands[n_bands];
-+ 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]);
-+
-+ Rast_set_window(region);
-+
-+ n_a_bands = 0;/*TODO realy needed?*/
-+ for(id_band = 0; id_band < n_bands; id_band++)
-+ {
-+ if(b_needed_bands[id_band])
-+ {
-+ G_debug(3, "Opening raster no. %d with name: %s", id_band, bands[id_band]);
-+
-+ /* 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,
-+ &bands_ids[0], NULL, NULL, scatt_conds->n_a_cats);
-+ return -1;
-+ }
-+
-+ 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,
-+ &bands_ids[0], NULL, NULL, scatt_conds->n_a_cats);
-+ return -1;
-+ }
-+
-+ //TODO check data type, minimum and maximum value
-+ data_type = Rast_get_map_type(fd_bands[n_a_bands]);
-+ //if(data_type != CELL)
-+ // return -1;
-+
-+ //What happens if it is not CELL tyoe
-+ chunks[id_band] = Rast_allocate_c_buf();
-+ null_chunks[id_band] = Rast_allocate_null_buf();
-+
-+ bands_ids[n_a_bands] = id_band;
-+
-+ ++n_a_bands;
-+ }
-+ }
-+
-+ 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;
-+ }
-+
-+ 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;
-+ }
-+
-+ 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;
-+ }
-+
-+ 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);
-+
-+ i_chunk = 0;
-+
-+ nrows = Rast_window_rows();
-+ chunk_size = Rast_window_cols();
-+
-+ for (i_row = 0; i_row < nrows; i_row++)
-+ {
-+ for(i_band = 0; i_band < n_a_bands; i_band++)
-+ {
-+ band_id = bands_ids[i_band];
-+ G_debug(3, "Reading data for band %d", band_id);
-+ Rast_get_c_row(fd_bands[i_band], chunks[band_id], i_row);
-+ Rast_get_null_value_row (fd_bands[i_band], null_chunks[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)
-+ {
-+ 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], &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 0;
-+}
-\ No newline at end of file
Copied: sandbox/turek/scatter_plot/testing_patch.diff (from rev 57286, sandbox/turek/scatter_plot/testing_pach.diff)
===================================================================
--- sandbox/turek/scatter_plot/testing_patch.diff (rev 0)
+++ sandbox/turek/scatter_plot/testing_patch.diff 2013-07-27 01:36:53 UTC (rev 57287)
@@ -0,0 +1,4189 @@
+Index: vector/v.edit/main.c
+===================================================================
+--- vector/v.edit/main.c (revision 57285)
++++ 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 57285)
++++ include/imagery.h (working copy)
+@@ -135,6 +135,41 @@
+
+ } IClass_statistics;
+
++/* 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;
++};
++
++struct scdScattData
++{
++ int n_vals;
++ //TODO void pointer???
++ unsigned int * b_conds_arr;
++ unsigned int * scatt_vals_arr;
++};
++
+ #define SIGNATURE_TYPE_MIXED 1
+
+ #define GROUPFILE "CURGROUP"
+Index: include/defs/vedit.h
+===================================================================
+--- include/defs/vedit.h (revision 57285)
++++ include/defs/vedit.h (working copy)
+@@ -34,7 +34,7 @@
+
+ /* 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: include/defs/imagery.h
+===================================================================
+--- include/defs/imagery.h (revision 57285)
++++ include/defs/imagery.h (working copy)
+@@ -110,6 +110,29 @@
+ 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 I_scd_free_scatt_data(struct scdScattData *);
++int I_scd_get_data_size(struct scdScattData *);
++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 I_create_cat_rast(struct Cell_head *, const char *);
++int I_insert_patch_to_cat_rast(const char *, struct Cell_head *, const char *);
++
++
+ /* sig.c */
+ int I_init_signatures(struct Signature *, int);
+ int I_new_signature(struct Signature *);
+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,631 @@
++"""!
++ 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
++
++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
++
++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):
++
++ self.scatts_dt.AddScattPlot(scatt_id = scatt_id)
++
++ scatt_conds = self.scatt_conds_dt.GetData({0 : []})
++ scatts = self.scatts_dt.GetData({0 : [scatt_id]})
++
++ 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)
++ self.scatts_dt.SetData(scatts)
++
++ def SetEditCatData(self, cat_id, scatt_id, bbox, value):
++
++ 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
++
++ self.ComputeCatScatts([cat_id])
++
++ 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)
++
++ 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 = None
++ self.bin_bands_f = []
++
++ self.region = {}
++
++ def GetRegion(self):
++ return self.region
++
++ def Create(self, bands):
++
++ self.bands = None
++ 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.region = self._parseRegion(region)
++
++ def GetBands(self):
++ return self.bands
++
++ 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
++
++ self.max_n_cats = 10
++
++ self.vals = 256 * 256
++
++ 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
++
++ if self.type == 0:
++ np_vals = np.zeros(self.vals, dtype = 'uint32')
++ elif self.type == 1:
++ #TODO solve proble with short
++ np_vals = np.zeros(self.vals, dtype = 'uint32')
++ else:
++ return -1
++
++ np_vals.shape = (256, 256)#TODO hack do it general
++
++ self.cats[cat_id][scatt_id] = {
++ 'np_vals' : np_vals
++ }
++
++ return 1
++
++ 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']}
++
++ 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)
++
++ #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] = self.cats[cat_id][scatt_id]['np_vals']
++
++ 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 idScattToBands(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 BandsToidScatt(band_1, band_2, n_bands):
++
++ if band_2 < band_1:
++ tmp = band_1
++ band_1 = band_2
++ band_2 = tmp
++
++
++ n_b1 = n_bands - 1
++
++ scatt_id = (band_1 * (2 * n_b1 + 1) - band_1 * band_1) / 2 + band_2 - band_1 - 1
++
++ return scatt_id
++
+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 @@
++"""!
++ at package scatt_plot.gthreading
++
++Classes:
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++
++import os
++import sys
++import time
++import threading
++import Queue
++
++import wx
++from core.gconsole import wxCmdRun, wxCmdDone, wxCmdPrepare
++
++class gThread(threading.Thread):
++ """!Thread for GRASS commands"""
++ requestId = 0
++
++ def __init__(self, receiver, requestQ=None, resultQ=None, **kwds):
++ """!
++ @param receiver event receiver (used in PostEvent)
++ """
++ threading.Thread.__init__(self, **kwds)
++
++ if requestQ is None:
++ self.requestQ = Queue.Queue()
++ else:
++ self.requestQ = requestQ
++
++ if resultQ is None:
++ self.resultQ = Queue.Queue()
++ else:
++ self.resultQ = resultQ
++
++ self.setDaemon(True)
++
++ self.receiver = receiver
++ self._want_abort_all = False
++
++ self.start()
++
++ def Run(self, *args, **kwds):
++ """!Run command in queue
++
++ @param args unnamed command arguments
++ @param kwds named command arguments
++
++ @return request id in queue
++ """
++ gThread.requestId += 1
++ self.requestQ.put((gThread.requestId, args, kwds))
++
++ return gThread.requestId
++
++ def GetId(self):
++ """!Get id for next command"""
++ return gThread.requestId + 1
++
++ def SetId(self, id):
++ """!Set starting id"""
++ gThread.requestId = id
++
++ def run(self):
++ os.environ['GRASS_MESSAGE_FORMAT'] = 'gui'
++ while True:
++ requestId, args, kwds = self.requestQ.get()
++ for key in ('callable', 'onDone', 'onPrepare', 'userData'):
++ if key in kwds:
++ vars()[key] = kwds[key]
++ del kwds[key]
++ else:
++ vars()[key] = None
++
++ requestTime = time.time()
++
++ #if self._want_abort_all and self.requestCmd is not None:
++ # self.requestCmd.abort()
++ # if self.requestQ.empty():
++ # self._want_abort_all = False
++
++ # prepare
++ if self.receiver:
++ event = wxCmdPrepare(type = 'method',
++ time=requestTime,
++ pid=requestId)
++
++ wx.PostEvent(self.receiver, event)
++
++ # run command
++ event = wxCmdRun(type = 'method',
++ pid=requestId)
++
++ wx.PostEvent(self.receiver, event)
++
++ time.sleep(.1)
++
++ ret = None
++ exception = None
++ #try:
++ ret = vars()['callable'](*args, **kwds)
++ #except Exception as e:
++ # exception = e;
++
++ self.resultQ.put((requestId, ret))
++
++ time.sleep(.1)
++
++
++ if self.receiver:
++ event = wxCmdDone(type = 'cmd',
++ kwds = kwds,
++ args = args, #TODO expand args to kwds
++ ret=ret,
++ exception=exception,
++ pid=requestId)
++
++ # send event
++ wx.PostEvent(self.receiver, event)
++
++ def abort(self, abortall=True):
++ """!Abort command(s)"""
++ if abortall:
++ self._want_abort_all = True
++ if self.requestQ.empty():
++ self._want_abort_all = False
+\ No newline at end of file
+Index: gui/wxpython/scatt_plot/dialogs.py
+===================================================================
+--- gui/wxpython/scatt_plot/dialogs.py (revision 0)
++++ gui/wxpython/scatt_plot/dialogs.py (working copy)
+@@ -0,0 +1,612 @@
++"""!
++ at package scatt_plot.dialogs
++
++ at brief GUI.
++
++Classes:
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++import os
++import sys
++
++import wx
++import wx.lib.mixins.listctrl as listmix
++import wx.lib.flatnotebook as FN
++import wx.aui
++
++from core import globalvar
++from core.gcmd import GException, GError, RunCommand
++
++from gui_core.gselect import Select
++from 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, BandsToidScatt
++from scatt_plot.plots import ScatterPlotWidget
++
++
++class ScattPlotMainDialog(wx.Dialog):
++ 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))
++
++ #TODO remove iclass parameter
++ 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)
++
++ # Fancy gui
++ self._mgr = wx.aui.AuiManager(self)
++ self._addPanes()
++ self._mgr.Update()
++
++ 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)
++
++ dlgSize = (220, 400)
++ self.SetMinSize(dlgSize)
++ self.SetInitialSize(dlgSize)
++
++ #fix goutput's pane size (required for Mac OSX)
++ #if self.gwindow:
++ # self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
++
++ def _doLayout(self):
++
++ sizer = wx.BoxSizer(wx.VERTICAL)
++
++ sizer.Add(item = self.notebook, proportion = 1,
++ flag = wx.EXPAND)
++
++ self.mainPanel.SetSizer(sizer)
++
++ sizer.Fit(self)
++ self.Layout()
++
++ #TODO split to panel?
++ def _createCategoryPage(self):
++ catsPanel = wx.Panel(parent = self)
++
++
++ self.notebook.AddPage(page = catsPanel,
++ text=_('Categories'),
++ name = 'categories')
++
++ 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)
++
++ AnalysisSizer = wx.BoxSizer(wx.VERTICAL)
++
++ catsSizer = wx.BoxSizer(wx.VERTICAL)
++
++ catsSizer.Add(item = self.toolbars['catsList'], proportion = 0)
++ catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND)
++
++ catsPanel.SetSizer(catsSizer)
++
++ 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))
++
++ self._mgr.AddPane(self.mainPanel,
++ wx.aui.AuiPaneInfo().
++ Name("tabs").CaptionVisible(visible = False).
++ Center().
++ Dockable(False).
++ CloseButton(False).Layer(0))
++
++ def OnCloseDialog(self, event):
++ """!Close dialog"""
++ self.scatt_mgr.CleanUp()
++ self.Destroy()
++
++ def OnSettings(self, event):
++ pass
++
++ def OnSetData(self, event):
++
++ dlg = SetDataDialog(parent=self)
++
++ if dlg.ShowModal() == wx.ID_OK:
++ bands = dlg.GetBands()
++ self.scatt_mgr.SetData(bands)
++
++ dlg.Destroy()
++
++
++ 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()
++
++ def OnSettings(self, event):
++ pass
++
++ def OnAddScattPl(self, event):
++
++ bands = self.scatt_mgr.GetBands()
++ if not bands:
++ GError(_('No data set for scatter plot.'))
++ return
++
++ dlg = AddScattPlotDialog(parent = self, bands = bands)
++
++ if dlg.ShowModal() == wx.ID_OK:
++ self.scatt_mgr.AddScattPlot(dlg.GetScattId())
++
++ dlg.Destroy()
++
++ def EditCatAdd(self):
++ self._setEditCat(tool_name = 'editCatAdd')
++
++ def EditCatRemove(self):
++ self._setEditCat(tool_name = 'editCatRemove')
++
++ def _setEditCat(self, tool_name):
++
++ 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.edit_cat_tools[i_tool_name]['toggle'] = False
++
++ toolbar = self.toolbars['catsList']
++ toolbar.ToggleTool(vars(toolbar)[i_tool_name], False)
++
++ self.edit_cat_tools[tool_name]['toggle'] = True
++ self.scatt_mgr.EditCat(edit_type = self.edit_cat_tools[tool_name]['type'])
++ return
++
++ self.scatt_mgr.EditCat(edit_type = None)
++ self.edit_cat_tools[tool_name]['toggle'] = False
++
++ def GetScattMgr(self):
++ return self.scatt_mgr
++
++
++class SetDataDialog(wx.Dialog):
++
++ def __init__(self, parent, id = wx.ID_ANY):
++
++ wx.Dialog.__init__(self, parent, title = ("Select imagery group "), id = id)
++
++ self.bands = []
++
++
++ self._createWidgets()
++ self.group.SetValue("testovaci_1")
++
++ 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.group = Select(parent = self, type = 'group',
++ size = globalvar.DIALOG_GSELECT_SIZE)
++
++ # buttons
++ self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
++
++ self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
++
++ self._layout()
++
++ def _layout(self):
++
++ border = wx.BoxSizer(wx.VERTICAL)
++ dialogSizer = wx.BoxSizer(wx.VERTICAL)
++
++ regionSizer = wx.BoxSizer(wx.HORIZONTAL)
++
++ dialogSizer.Add(item = self._addSelectSizer(title = self.group_label,
++ sel = self.group))
++
++ # buttons
++ self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
++
++ self.btnsizer.Add(item = self.btn_close, proportion = 0,
++ flag = wx.ALL | wx.ALIGN_CENTER,
++ border = 10)
++
++ self.btnsizer.Add(item = self.btn_ok, proportion = 0,
++ flag = wx.ALL | wx.ALIGN_CENTER,
++ border = 10)
++
++ dialogSizer.Add(item = self.btnsizer, proportion = 0,
++ flag = wx.ALIGN_CENTER)
++
++ border.Add(item = dialogSizer, proportion = 0,
++ flag = wx.ALL, border = 5)
++
++ self.SetSizer(border)
++ self.Layout()
++ self.Fit()
++
++ # bindings
++ self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
++ self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
++
++ def _addSelectSizer(self, title, sel):
++ """!Helper layout function.
++ """
++ selSizer = wx.BoxSizer(orient = wx.VERTICAL)
++
++ selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
++ selTitleSizer.Add(item = title, proportion = 1,
++ flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
++
++ selSizer.Add(item = selTitleSizer, proportion = 0,
++ flag = wx.EXPAND)
++
++ selSizer.Add(item = sel, proportion = 1,
++ flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
++ border = 5)
++
++ return selSizer
++
++ def GetBands(self):
++
++ return self.bands
++
++ def OnClose(self, event):
++ """!Close dialog
++ """
++ if not self.IsModal():
++ self.Destroy()
++ event.Skip()
++
++ def OnOk(self, event):
++ """!
++ """
++ ret, stdout, err_msg = RunCommand("i.group",
++ getErrorMsg = True,
++ read = True,
++ quiet = True,
++ group = self.group.GetValue().strip(),
++ flags = 'g')
++
++ if ret != 0:
++ GError("%s module failed:\n%s" % ("<i.group>", err_msg))
++ return
++
++ self.bands = stdout.split('\n')
++
++ 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()
++
++class AddScattPlotDialog(wx.Dialog):
++
++ def __init__(self, parent, bands, id = wx.ID_ANY):
++
++ wx.Dialog.__init__(self, parent, title = ("Add scatter plot"), id = id)
++
++ self.bands = bands
++
++ self.scatt_id = None
++
++ self._createWidgets()
++
++ def _createWidgets(self):
++
++ self.labels = {}
++ self.params = {}
++
++ self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
++
++ self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
++ choices = self.bands,
++ style = wx.CB_READONLY, size = (350, 30))
++
++ self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 2:"))
++
++ self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
++ choices = self.bands,
++ style = wx.CB_READONLY, size = (350, 30))
++
++ # buttons
++ self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
++
++ self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
++
++ self._layout()
++
++ def _layout(self):
++
++ border = wx.BoxSizer(wx.VERTICAL)
++ dialogSizer = wx.BoxSizer(wx.VERTICAL)
++
++ regionSizer = wx.BoxSizer(wx.HORIZONTAL)
++
++ dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label,
++ sel = self.band_1_ch))
++
++ dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label,
++ sel = self.band_2_ch))
++
++ # buttons
++ self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
++
++ self.btnsizer.Add(item = self.btn_close, proportion = 0,
++ flag = wx.ALL | wx.ALIGN_CENTER,
++ border = 10)
++
++ self.btnsizer.Add(item = self.btn_ok, proportion = 0,
++ flag = wx.ALL | wx.ALIGN_CENTER,
++ border = 10)
++
++ dialogSizer.Add(item = self.btnsizer, proportion = 0,
++ flag = wx.ALIGN_CENTER)
++
++ border.Add(item = dialogSizer, proportion = 0,
++ flag = wx.ALL, border = 5)
++
++ self.SetSizer(border)
++ self.Layout()
++ self.Fit()
++
++ # bindings
++ self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
++ self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
++
++ def _addSelectSizer(self, title, sel):
++ """!Helper layout function.
++ """
++ selSizer = wx.BoxSizer(orient = wx.VERTICAL)
++
++ selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
++ selTitleSizer.Add(item = title, proportion = 1,
++ flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
++
++ selSizer.Add(item = selTitleSizer, proportion = 0,
++ flag = wx.EXPAND)
++
++ selSizer.Add(item = sel, proportion = 1,
++ flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
++ border = 5)
++
++ return selSizer
++
++ def OnClose(self, event):
++ """!Close dialog
++ """
++ if not self.IsModal():
++ self.Destroy()
++ event.Skip()
++
++ def OnOk(self, event):
++ """!
++ """
++ band_1 = self.band_1_ch.GetSelection()
++ band_2 = self.band_2_ch.GetSelection()
++
++
++ if band_1 == band_2:
++ GError(_("Selected bands must be different."))
++ return
++
++ #TODO axes selection
++ if band_1 > band_2:
++ tmp_band = band_2
++ band_2 = band_1
++ band_1 = band_2
++
++ self.scatt_id = BandsToidScatt(band_1, band_2, len(self.bands))
++
++ event.Skip()
++
++ def GetScattId(self):
++ return self.scatt_id
++
++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)
++
++ def GetPlot(self):
++ return self.scatt
++
++ def _doLayout(self):
++ self.main_sizer = wx.BoxSizer(wx.VERTICAL)
++ self.main_sizer.Add(self.self)
++
++ self.panel.SetSizer(self.main_sizer)
++ self.main_sizer.Fit(self)
++
++ def OnPlotClosed(self, scatt_id):
++ self.Destroy()
++
++class CategoryListCtrl(wx.ListCtrl,
++ listmix.ListCtrlAutoWidthMixin,
++ listmix.TextEditMixin):
++
++ def __init__(self, parent, cats_mgr, id = wx.ID_ANY):
++
++ wx.ListCtrl.__init__(self, parent, id,
++ style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES)
++ self.columns = ((_('Category name'), 'name'),
++ (_('Color'), 'color'))
++ self.Populate(columns = self.columns)
++
++ self.cats_mgr = cats_mgr
++ self.SetItemCount(len(self.cats_mgr.GetCategories()))
++
++ self.rightClickedItemIdx = wx.NOT_FOUND
++
++ listmix.ListCtrlAutoWidthMixin.__init__(self)
++
++ listmix.TextEditMixin.__init__(self)
++
++ self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnEdit)
++ self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSel)
++
++ self.cats_mgr.setCategoryAttrs.connect(self.Update)
++ self.cats_mgr.deletedCategory.connect(self.Update)
++ self.cats_mgr.addedCategory.connect(self.Update)
++
++ def Update(self, **kwargs):
++ self.SetItemCount(len(self.cats_mgr.GetCategories()))
++ self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++
++ def InitCoreCats(self):
++ self.SetItemCount(len(self.cats_mgr.GetCategories()))
++ self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++
++ def SetVirtualData(self, row, column, text):
++ attr = self.columns[column][1]
++ if attr == 'name':
++ try:
++ text.encode('ascii')
++ except UnicodeEncodeError:
++ GMessage(parent = self, message = _("Please use only ASCII characters."))
++ return
++
++ cat_id = self.cats_mgr.GetCategories()[row]
++
++ self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
++ self.cats_mgr.SetCategoryAttrs(cat_id, {attr : text})
++ self.cats_mgr.setCategoryAttrs.connect(self.Update)
++
++ self.Select(row)
++
++ def Populate(self, columns):
++ for i, col in enumerate(columns):
++ self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
++
++ self.SetColumnWidth(0, 100)
++ self.SetColumnWidth(1, 100)
++
++ def AddCategory(self):
++
++ self.cats_mgr.addedCategory.disconnect(self.Update)
++ cat_id = self.cats_mgr.AddCategory()
++ self.cats_mgr.addedCategory.connect(self.Update)
++
++ if cat_id < 0:
++ GError(_("Maximum limit of categories number was reached."))
++ return
++ self.SetItemCount(len(self.cats_mgr.GetCategories()))
++
++ def DeleteCategory(self):
++ indexList = sorted(self.GetSelectedIndices(), reverse = True)
++ cats = []
++ for i in indexList:
++ # remove temporary raster
++ cat_id = self.cats_mgr.GetCategories()[i]
++
++ cats.append(cat_id)
++
++ self.cats_mgr.deletedCategory.disconnect(self.Update)
++ self.cats_mgr.DeleteCategory(cat_id)
++ self.cats_mgr.deletedCategory.connect(self.Update)
++
++ self.SetItemCount(len(self.cats_mgr.GetCategories()))
++
++ def OnSel(self, event):
++ self.cats_mgr.SetSelectedCat(event.GetIndex() + 1)
++
++ event.Skip()
++
++ def GetSelectedIndices(self, state = wx.LIST_STATE_SELECTED):
++ indices = []
++ lastFound = -1
++ while True:
++ index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state)
++ if index == -1:
++ break
++ else:
++ lastFound = index
++ indices.append(index)
++ return indices
++
++ def OnEdit(self, event):
++ currentItem = event.m_itemIndex
++ currentCol = event.m_col
++
++ if currentCol == 1:
++ dlg = wx.ColourDialog(self)
++ dlg.GetColourData().SetChooseFull(True)
++
++ if dlg.ShowModal() == wx.ID_OK:
++ color = dlg.GetColourData().GetColour().Get()
++ color = ':'.join(map(str, color))
++ self.SetVirtualData(currentItem, currentCol, color)
++ dlg.Destroy()
++ wx.CallAfter(self.SetFocus)
++
++ event.Skip()
++
++
++ def DeselectAll(self):
++ """!Deselect all items"""
++ indexList = self.GetSelectedIndices()
++ for i in indexList:
++ self.Select(i, on = 0)
++
++ # no highlight
++ self.OnCategorySelected(None)
++
++ def OnGetItemText(self, item, col):
++ attr = self.columns[col][1]
++ cat_id = self.cats_mgr.GetCategories()[item]
++
++ return self.cats_mgr.GetCategoryAttrs(cat_id)[attr]
++
++ def OnGetItemImage(self, item):
++ return -1
++
++ def OnGetItemAttr(self, item):
++ return None
+Index: gui/wxpython/scatt_plot/toolbars.py
+===================================================================
+--- gui/wxpython/scatt_plot/toolbars.py (revision 0)
++++ gui/wxpython/scatt_plot/toolbars.py (working copy)
+@@ -0,0 +1,106 @@
++"""!
++ at package scatt_plot.toolbars
++
++ at brief Scatter plot - toolbars
++
++Classes:
++ - toolbars::MainToolbar
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++
++
++import wx
++
++from icons.icon import MetaIcon
++from gui_core.toolbars import BaseToolbar, BaseIcons
++from core.gcmd import RunCommand
++
++class MainToolbar(BaseToolbar):
++ """!Main toolbar
++ """
++ def __init__(self, parent):
++ BaseToolbar.__init__(self, parent)
++
++ self.InitToolbar(self._toolbarData())
++
++ # realize the toolbar
++ self.Realize()
++
++ def _toolbarData(self):
++
++ icons = {
++ 'set_data' : MetaIcon(img = 'layer-raster-add',
++ label = _('Set input raster data for plots')),
++ 'settings' : BaseIcons['settings'].SetLabel( _('Ssettings')),
++ 'help' : MetaIcon(img = 'help',
++ label = _('Show manual')),
++ 'add_scatt_pl' : MetaIcon(img = 'layer-raster-analyze',
++ label = _('Add scatter plot'))
++ }
++
++ return self._getToolbarData((
++ ('sat_data', icons["set_data"],
++ self.parent.OnSetData),
++ (None, ),
++ ('add_scatt', icons["add_scatt_pl"],
++ self.parent.OnAddScattPl),
++ #('settings', icons["settings"],
++ # self.parent.OnSettings),
++ #('help', icons["help"],
++ # self.OnHelp),
++ ("quit", BaseIcons['quit'],
++ self.parent.OnCloseDialog)
++ ))
++
++ def OnHelp(self, event) :
++ RunCommand('g.manual',
++ entry = 'wxGUI.scatt_plot')
++
++class CategoriesToolbar(BaseToolbar):
++
++ def __init__(self, parent, cats_list, scatts_dlg):
++ BaseToolbar.__init__(self, parent)
++ self.cats_list = cats_list
++ self.scatts_dlg = scatts_dlg
++
++ self.InitToolbar(self._toolbarData())
++
++
++ # realize the toolbar
++ self.Realize()
++
++
++ def _toolbarData(self):
++
++ icons = {
++ 'editCatAdd' : MetaIcon(img = 'polygon-create',
++ label = _('Add region to category mode')),
++ 'editCatRemove' : MetaIcon(img = 'polygon-delete',
++ label = _('Remove region to category mode')),
++ 'addCat' : MetaIcon(img = 'layer-add',
++ label = _('Add category')),
++ 'deleteCat' : MetaIcon(img = 'layer-remove',
++ label = _('Delete category'))
++ }
++
++ return self._getToolbarData((('editCatAdd', icons['editCatAdd'],
++ lambda event: self.scatts_dlg.EditCatAdd(),
++ wx.ITEM_CHECK),
++ ('editCatRemove', icons['editCatRemove'],
++ lambda event: self.scatts_dlg.EditCatRemove(),
++ wx.ITEM_CHECK),
++ (None, ),
++ ('addCat', icons["addCat"],
++ lambda event: self.cats_list.AddCategory()),
++ ('deleteCat', icons["deleteCat"],
++ lambda event: self.cats_list.DeleteCategory())))
++
++ def GetToolId(self, toolName): #TODO can be useful in base
++
++ return vars(self)[toolName]
+\ No newline at end of file
+Index: gui/wxpython/scatt_plot/core_c.py
+===================================================================
+--- gui/wxpython/scatt_plot/core_c.py (revision 0)
++++ gui/wxpython/scatt_plot/core_c.py (working copy)
+@@ -0,0 +1,211 @@
++"""!
++ at package scatt_plot.scatt_plot
++
++ at brief Functions which work with scatter plot c code.
++
++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)
++"""
++
++from multiprocessing import Process, Queue
++
++from ctypes import *
++try:
++ from grass.lib.imagery import *
++ from grass.lib.gis import Cell_head, G_get_window
++
++except ImportError, e:
++ sys.stderr.write(_("Loading imagery lib failed"))
++
++def ComputeScatts(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out):
++
++ #return _computeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out)
++
++ # Queue object for interprocess communication
++ q = Queue()
++
++ # The separate render process
++ p = Process(target=_computeScattsProcess, args=(region, scatt_conds, bands,
++ n_bands, scatts, cats_rasts_in, cats_rasts_out, q))
++ p.start()
++ ret = q.get()
++ p.join()
++
++ return ret[0], ret[1]
++
++def UpdateCatRast(patch_rast, region, cat_rast):
++
++ #return ComputeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts)
++ # Queue object for interprocess communication
++
++ #_updateCatRastProcess(patch_rast, region, cat_rast, None)
++ #return
++ q = Queue()
++ # The separate render process
++ p = Process(target=_updateCatRastProcess, args=(patch_rast, region, cat_rast, q))
++ p.start()
++ #ret = q.get()
++ p.join()
++
++ #return ret[0], ret[1]
++
++def CreateCatRast(region, cat_rast):
++
++ cell_head = _regionToCellHead(region)
++ I_create_cat_rast(pointer(cell_head), cat_rast)
++
++def _computeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out, output_queue):
++
++ #TODO names for types not 0 and 1?
++ sccats_c, vals_dt = _getComputationStruct(scatts, 0, n_bands)
++ scatt_conds_c, vals_dt2 = _getComputationStruct(scatt_conds, 1, n_bands)
++
++ char_bands = _stringListToCharArr(bands)
++ char_cats_rasts_out = _stringListToCharArr(cats_rasts_out)
++ char_cats_rasts_in = _stringListToCharArr(cats_rasts_in)
++
++ cell_head = _regionToCellHead(region)
++
++ ret = I_compute_scatts(pointer(cell_head),
++ pointer(scatt_conds_c),
++ pointer(char_bands),
++ n_bands,
++ pointer(sccats_c),
++ pointer(char_cats_rasts_in),
++ pointer(char_cats_rasts_out))
++
++ I_sc_free_cats(pointer(sccats_c))
++ I_sc_free_cats(pointer(scatt_conds_c))
++
++ output_queue.put((ret, scatts))
++ #return (ret, scatts)
++
++def _regionToCellHead(region):
++ cell_head = struct_Cell_head()
++ G_get_window(pointer(cell_head))
++
++ convert_dict = {'n' : 'north', 'e' : 'east',
++ 'w' : 'west', 's' : 'south',
++ 'nsres' : 'ns_res',
++ 'ewres' : 'ew_res'}
++
++ for k, v in region.iteritems():
++ if k in ["rows", "cols", "cells"]:
++ v = int(v)
++ else:
++ v = float(v)
++
++ if convert_dict.has_key(k):
++ k = convert_dict[k]
++
++ setattr(cell_head, k, v)
++
++ return cell_head
++
++def _stringListToCharArr(str_list):
++
++ arr = c_char_p * len(str_list)
++ char_arr = arr()
++ for i, st in enumerate(str_list):
++ if st:
++ char_arr[i] = st
++ else:
++ char_arr[i] = None
++
++ return char_arr
++
++def _getComputationStruct(cats, cats_type, n_bands):
++
++ sccats = struct_scCats()
++ I_sc_init_cats(pointer(sccats), c_int(n_bands), c_int(cats_type));
++
++ #for i in range(sccats.n_a_cats):
++ # cat_id = sccats.cats_ids[i]
++ # I_sc_delete_cat(pointer(sccats), cat_id)
++ # i -= 1
++
++ vals_dt = []
++ for cat_id, scatt_ids in cats.iteritems():
++ I_sc_add_cat(pointer(sccats), cat_id)
++
++ for scatt_id, dt in scatt_ids.iteritems():
++ # if key is missing condition is always True (full scatter plor is computed)
++ if cats[cat_id].has_key(scatt_id):
++
++ vals = dt["np_vals"]
++ #TODO hack
++ vals.shape = (256 * 256)
++
++ c_uint_p = ctypes.POINTER(ctypes.c_uint)
++ scatt_vals = scdScattData()
++ if cats_type == 0:
++ vals[:] = 0
++ scatt_vals.scatt_vals_arr = vals.ctypes.data_as(c_uint_p)
++
++ else:
++ #TODO solve proble with short integer
++ scatt_vals.b_conds_arr = vals.ctypes.data_as(c_uint_p)
++
++ vals_dt.append(scatt_vals)
++
++ #vals_dt.append(data_p)
++ vals.shape = (256, 256)
++ I_sc_insert_scatt_data(pointer(sccats),
++ pointer(scatt_vals),
++ cat_id, scatt_id)
++
++ return sccats, vals_dt
++
++def _updateCatRastProcess(patch_rast, region, cat_rast, output_queue):
++
++ #TODO names for types not 0 and 1?
++
++ cell_head = _regionToCellHead(region)
++
++
++ cat_rast
++ I_insert_patch_to_cat_rast(patch_rast,
++ pointer(cell_head),
++ cat_rast)
++
++ #print re
++ #output_queue.put((ret, scatts))
++ #return (ret, scatts)
++
++"""
++class A:
++ def __init__(self):
++ self.i = 0
++
++ def incr(self):
++ self.i += 1
++ return self.i
++
++def worker(input, output):
++ print "ahoj"
++ for func, args in iter(input.get, 'STOP'):
++ print "jedu"
++ result = func.incr
++ output.put(result)
++
++def test():
++ # Create queues
++ task_queue = Queue()
++ done_queue = Queue()
++
++ # Start worker processes
++ a = A()
++
++ prc = Process(target=worker, args=(task_queue, done_queue)).start()
++ task_queue.put((a,1))
++
++ data = done_queue.get()
++ print data
++ task_queue.put('STOP')
++"""
+Index: gui/wxpython/scatt_plot/__init__.py
+===================================================================
+--- gui/wxpython/scatt_plot/__init__.py (revision 0)
++++ gui/wxpython/scatt_plot/__init__.py (working copy)
+@@ -0,0 +1,8 @@
++all = [
++ 'dialogs',
++ 'gthreading',
++ 'plots',
++ 'sc_pl_core',
++ 'toolbars',
++ 'core_c',
++ ]
+Index: gui/wxpython/scatt_plot/plots.py
+===================================================================
+--- gui/wxpython/scatt_plot/plots.py (revision 0)
++++ gui/wxpython/scatt_plot/plots.py (working copy)
+@@ -0,0 +1,185 @@
++"""!
++ at package scatt_plot.dialogs
++
++ at brief Ploting widgets.
++
++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 wx
++import numpy as np
++import random
++try:
++ haveMatPlot = True
++ import matplotlib
++ matplotlib.use('WXAgg')
++ from matplotlib.figure import Figure
++ from matplotlib.backends.backend_wxagg import \
++ FigureCanvasWxAgg as FigCanvas, \
++ NavigationToolbar2WxAgg as NavigationToolbar
++except ImportError:
++ haveMatPlot = False
++
++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
++
++ self._createWidgets()
++ self._doLayout()
++ self.scatt_id = scatt_id
++ self.scatt_mgr = scatt_mgr
++ self.press_coords = None
++
++ self.cidpress = None
++ self.cidrelease = None
++
++ def StartCategoryEdit(self):
++ 'connect to all the events we need'
++ self.cidpress = self.canvas.mpl_connect(
++ 'button_press_event', self.OnPress)
++ self.cidrelease = self.canvas.mpl_connect(
++ 'button_release_event', self.OnRelease)
++ #self.cidmotion = self.canvas.mpl_connect(
++ # 'motion_notify_event', self.OnRelease)
++
++ def OnPress(self, event):
++ 'on button press we will see if the mouse is over us and store some data'
++
++ if event.xdata and event.ydata:
++ self.press_coords = { 'x' : event.xdata, 'y' : event.ydata}
++ else:
++ self.press_coords = None
++
++ def OnRelease(self, event):
++ 'on release we reset the press data'
++
++ if event.xdata and event.ydata and self.press_coords:
++
++ bbox = {}
++ if event.ydata > self.press_coords['y']:
++ bbox['up_y'] = event.ydata
++ bbox['btm_y'] = self.press_coords['y']
++ else:
++ bbox['up_y'] = self.press_coords['y']
++ bbox['btm_y'] = event.ydata
++
++ if event.xdata > self.press_coords['x']:
++ bbox['up_x'] = event.xdata
++ bbox['btm_x'] = self.press_coords['x']
++ else:
++ bbox['up_x'] = self.press_coords['x']
++ bbox['btm_x'] = event.xdata
++
++ self.scatt_mgr.SetEditCatData(self.scatt_id, bbox)
++
++ def StopCategoryEdit(self):
++ 'disconnect all the stored connection ids'
++
++ if self.cidpress:
++ self.canvas.mpl_disconnect(self.cidpress)
++ if self.cidrelease:
++ self.canvas.mpl_disconnect(self.cidrelease)
++ #self.canvas.mpl_disconnect(self.cidmotion)
++
++ def _createWidgets(self):
++
++ # Create the mpl Figure and FigCanvas objects.
++ # 5x4 inches, 100 dots-per-inch
++ #
++ self.dpi = 100
++ self.fig = Figure((5.0, 4.0), dpi=self.dpi)
++ self.canvas = FigCanvas(self, -1, self.fig)
++
++ # Since we have only one plot, we can use add_axes
++ # instead of add_subplot, but then the subplot
++ # configuration tool in the navigation toolbar wouldn't
++ # work.
++ #
++ self.axes = self.fig.add_subplot(111)
++
++ # Bind the 'pick' event for clicking on one of the bars
++ #
++ self.canvas.mpl_connect('button_press_event', self.on_pick)
++
++
++ # Create the navigation toolbar, tied to the canvas
++ #
++ self.toolbar = NavigationToolbar(self.canvas)
++
++ 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.SetSizer(self.main_sizer)
++ self.main_sizer.Fit(self)
++
++ def Plot(self, scatts, styles):
++ """ Redraws the figure
++ """
++
++ self.axes.clear()
++ for cat_id, cat in scatts.iteritems():
++ if cat_id == 0:
++ cmap = matplotlib.cm.jet
++ cmap.set_bad('w',1.)
++ cmap._init()
++ cmap._lut[len(cmap._lut) - 1, -1] = 0
++ else:
++ colors = styles[cat_id]['color'].split(":")
++
++ cmap = matplotlib.cm.jet
++ cmap.set_bad('w',1.)
++ cmap._init()
++ cmap._lut[len(cmap._lut) - 1, -1] = 0
++ cmap._lut[:, 0] = int(colors[0])/255.0
++ cmap._lut[:, 1] = int(colors[1])/255.0
++ cmap._lut[:, 2] = int(colors[2])/255.0
++
++ masked_cat = np.ma.masked_less_equal(cat, 0)
++
++ self.axes.imshow(masked_cat, cmap = cmap, interpolation='nearest')
++
++ self.canvas.draw()
++
++ def on_pick(self, event):
++ pass
++ # The event received here is of the type
++ # matplotlib.backend_bases.PickEvent
++ #
++ # It carries lots of information, of which we're using
++ # only a small amount here.
++ #
++ #box_points = event.x
++
++ #msg = "You've clicked on a bar with coords:\n"
++
++ #dlg = wx.MessageDialog(
++ # self,
++ # msg,
++ # "Click!",
++ # wx.OK | wx.ICON_INFORMATION)
++
++ #dlg.ShowModal()
++ #dlg.Destroy()
++
++ def on_exit(self, event):
++
++ self.CleanUp()
++
++ def CleanUp(self):
++
++ self.parent.OnPlotClosed(self.scatt_id)
++ self.Destroy()
+\ No newline at end of file
+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,513 @@
++"""!
++ 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, BandsToidScatt
++
++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
++
++ wx.EvtHandler.__init__(self)
++ self.giface = giface
++ self.mapDisp = giface.GetMapDisplay()
++ self.mapWin = giface.GetMapWindow()
++
++ 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)
++ else:
++ self.mapWin_conn = None
++ self.iclass_conn = None
++
++ self.tasks_pids = {
++ 'add_scatt' : -1,
++ 'set_data' : -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
++ self.tasks_pids['set_data'] = self.thread.GetId()
++ self.thread.Run(callable = self.core.SetData, bands = bands)
++
++ def SetDataDone(self, event):
++ self.data_set = True
++ self.cats_mgr.InitCoreCats()
++
++ def OnOutput(self, event):
++ """!Print thread output according to debug level.
++ """
++ print event.text
++
++ def GetBands(self):
++ return self.core.GetBands()
++
++ def AddScattPlot(self, scatt_id):
++
++ self.tasks_pids['add_scatt'] = 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)
++
++ 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.ComputeCatScatts,
++ 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 self.tasks_pids['add_scatt'] == event.pid:
++ self.AddScattPlotDone(event)
++ 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 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/vdigit/wxdigit.py
+===================================================================
+--- gui/wxpython/vdigit/wxdigit.py (revision 57285)
++++ gui/wxpython/vdigit/wxdigit.py (working copy)
+@@ -17,7 +17,7 @@
+ (and NumPy would be an excellent candidate for acceleration via
+ e.g. OpenCL or CUDA; I'm surprised it hasn't happened already).
+
+-(C) 2007-2011 by the GRASS Development Team
++(C) 2007-2011, 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.
+@@ -27,6 +27,8 @@
+
+ import grass.script.core as grass
+
++from grass.pydispatch.signal import Signal
++
+ from core.gcmd import GError
+ from core.debug import Debug
+ from core.settings import UserSettings
+@@ -176,7 +178,17 @@
+
+ if self.poMapInfo:
+ self.InitCats()
+-
++
++ #TODO signal for errors?
++ self.featureAdded = Signal('IVDigit.featureAdded')
++ self.areasDeleted = Signal('IVDigit.areasDeleted')
++ self.vertexMoved = Signal('IVDigit.vertexMoved')
++ self.vertexAdded = Signal('IVDigit.vertexAdded')
++ self.vertexRemoved = Signal('IVDigit.vertexRemoved')
++ self.featuresDeleted = Signal('IVDigit.featuresDeleted')
++ self.featuresMoved = Signal('IVDigit.featuresMoved')
++ self.lineEdited = Signal('IVDigit.lineEdited')
++
+ def __del__(self):
+ Debug.msg(1, "IVDigit.__del__()")
+ Vect_destroy_line_struct(self.poPoints)
+@@ -394,7 +406,6 @@
+
+ @return tuple (number of added features, feature ids)
+ """
+-
+ layer = self._getNewFeaturesLayer()
+ cat = self._getNewFeaturesCat()
+
+@@ -419,10 +430,14 @@
+ return (-1, None)
+
+ self.toolbar.EnableUndo()
+-
+- return self._addFeature(vtype, points, layer, cat,
+- self._getSnapMode(), self._display.GetThreshold())
+-
++
++ 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]})
++
++ return ret
++
+ def DeleteSelectedLines(self):
+ """!Delete selected features
+
+@@ -434,16 +449,25 @@
+ # colect categories for delete if requested
+ deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
+ catDict = dict()
++
++ old_geoms = []
++ old_areas_cats = []
+ if deleteRec:
+ for i in self._display.selected['ids']:
++
+ 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))
++
+ cats = self.poCats.contents
+- for j in range(cats.n_cats):
+- if cats.field[j] not in catDict.keys():
+- catDict[cats.field[j]] = list()
+- catDict[cats.field[j]].append(cats.cat[j])
++
++ # catDict was not used -> put into comment
++ #for j in range(cats.n_cats):
++ # if cats.field[j] not in catDict.keys():
++ # catDict[cats.field[j]] = list()
++ # catDict[cats.field[j]].append(cats.cat[j])
+
+ poList = self._display.GetSelectedIList()
+ nlines = Vedit_delete_lines(self.poMapInfo, poList)
+@@ -456,7 +480,8 @@
+ self._deleteRecords(cats)
+ self._addChangeset()
+ self.toolbar.EnableUndo()
+-
++ self.featuresDeleted.emit(old_geoms = old_geoms, old_areas_cats = old_areas_cats)
++
+ return nlines
+
+ def _deleteRecords(self, cats):
+@@ -512,22 +537,123 @@
+
+ @return number of deleted
+ """
++ if len(self._display.selected['ids']) < 1:
++ return 0
++
+ poList = self._display.GetSelectedIList()
+ cList = poList.contents
+
+ nareas = 0
++ old_geoms = []
++ old_areas_cats = []
++
+ for i in range(cList.n_values):
++
+ if Vect_get_line_type(self.poMapInfo, cList.value[i]) != GV_CENTROID:
+ continue
+-
++
++ area = Vect_get_centroid_area(self.poMapInfo, cList.value[i]);
++ if area > 0:
++ geoms, cats = self._getaAreaGeomsCats(area)
++ old_geoms += geoms
++ old_areas_cats += cats
++
+ nareas += Vedit_delete_area_centroid(self.poMapInfo, cList.value[i])
+
+ if nareas > 0:
+ self._addChangeset()
+ self.toolbar.EnableUndo()
++ self.areasDeleted.emit(old_geoms = old_geoms, old_areas_cats = old_areas_cats)
++
++ return nareas
++
++
++ def _getaAreaGeomsCats(self, area):
++
++ po_b_list = Vect_new_list()
++ Vect_get_area_boundaries(self.poMapInfo, area, po_b_list);
++ b_list = po_b_list.contents
++
++ geoms = []
++ areas_cats = []
++
++ if b_list.n_values > 0:
++ for i_line in range(b_list.n_values):
++
++ line = b_list.value[i_line];
++
++ geoms.append(self._getGeom(abs(line)))
++ areas_cats.append(self._getLineAreasCategories(abs(line)))
+
+- return nareas
++ Vect_destroy_list(po_b_list);
++
++ return geoms, areas_cats
++
++ def _getLineAreasCategories(self, ln_id):
++
++ ltype = Vect_read_line(self.poMapInfo, None, None, ln_id)
++ if ltype != GV_BOUNDARY:
++ return []
++
++ cats = [None, None]
++
++ left = c_int()
++ right = c_int()
++
++ if Vect_get_line_areas(self.poMapInfo, ln_id, pointer(left), pointer(right)) == 1:
++ areas = [left.value, right.value]
++
++ for i, a in enumerate(areas):
++ if a > 0:
++ centroid = Vect_get_area_centroid(self.poMapInfo, a)
++ if centroid <= 0:
++ continue
++ c = self._getCategories(centroid)
++ if c:
++ cats[i] = c
++
++ return cats
++
++ def _getCategories(self, ln_id):
++
++ poCats = Vect_new_cats_struct()
++ if Vect_read_line(self.poMapInfo, None, poCats, ln_id) < 0:
++ Vect_destroy_cats_struct(poCats)
++ return None
++
++ cCats = poCats.contents
++
++ cats = {}
++ for j in range(cCats.n_cats):
++ if cats.has_key(cCats.field[j]):
++ cats[cCats.field[j]].append(cCats.cat[j])
++ else:
++ cats[cCats.field[j]] = [cCats.cat[j]]
+
++ Vect_destroy_cats_struct(poCats)
++ return cats
++
++ def _getGeom(self, ln_id):
++
++ poPoints = Vect_new_line_struct()
++ if Vect_read_line(self.poMapInfo, poPoints, None, ln_id) < 0:
++ Vect_destroy_line_struct(poPoints)
++ return None
++
++ geom = self._convertGeom(poPoints)
++ Vect_destroy_line_struct(poPoints)
++ return geom
++
++ def _convertGeom(self, poPoints):
++
++ Points = poPoints.contents
++
++ pts_geom = []
++ for j in range(Points.n_points):
++ pts_geom.append((Points.x[j], Points.y[j]))
++
++ return pts_geom
++
+ def MoveSelectedLines(self, move):
+ """!Move selected features
+
+@@ -536,16 +662,39 @@
+ if not self._checkMap():
+ return -1
+
++ nsel = len(self._display.selected['ids'])
++ if nsel < 1:
++ return -1
++
+ thresh = self._display.GetThreshold()
+ snap = self._getSnapMode()
+
+ poList = self._display.GetSelectedIList()
++
++ old_geoms = []
++ 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()
+ 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)
++
+ Vect_destroy_list(poList)
+
++ cList = poNewIds.contents
++
++ if nlines > 0:
++ new_areas_cats = []
++ for i in range(cList.n_values):
++ new_id = cList.value[i]
++ new_areas_cats.append(self._getLineAreasCategories(new_id))
++
++ 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 @@
+ if nlines > 0:
+ self._addChangeset()
+ self.toolbar.EnableUndo()
+-
++
++ self.featuresMoved.emit(move = move,
++ old_geoms = old_geoms,
++ old_areas_cats = old_areas_cats,
++ new_areas_cats = new_areas_cats)
+ return nlines
+
+ def MoveSelectedVertex(self, point, move):
+@@ -571,20 +724,33 @@
+
+ if len(self._display.selected['ids']) != 1:
+ return -1
+-
++
++ # move only first found vertex in bbox
++ poList = self._display.GetSelectedIList()
++
++ cList = poList.contents
++ old_geom = self._getGeom(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)
+-
+- # move only first found vertex in bbox
+- poList = self._display.GetSelectedIList()
++
++ poNewIds = Vect_new_list()
+ 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(),
+ move[0], move[1], 0.0,
+- 1, self._getSnapMode())
++ 1, self._getSnapMode(), poNewIds)
+ Vect_destroy_list(poList)
+-
++
++ new_id = poNewIds.contents.value[0]
++ Vect_destroy_list(poNewIds)
++
++ if new_id > -1:
++ new_geom = self._getGeom(new_id)
++ new_areas_cats = self._getLineAreasCategories(new_id)
++
+ if moved > 0 and self._settings['breakLines']:
+ self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
+ None)
+@@ -592,7 +758,13 @@
+ if moved > 0:
+ self._addChangeset()
+ self.toolbar.EnableUndo()
+-
++
++ if new_id > -1:
++ self.vertexMoved.emit(new_geom = new_geom,
++ new_areas_cats = new_areas_cats,
++ old_areas_cats = old_areas_cats,
++ old_geom = old_geom)
++
+ return moved
+
+ def AddVertex(self, coords):
+@@ -681,6 +853,9 @@
+ self._error.ReadLine(line)
+ return -1
+
++ old_geom = self._getGeom(line)
++ old_areas_cats = self._getLineAreasCategories(line)
++
+ # build feature geometry
+ Vect_reset_line(self.poPoints)
+ for p in coords:
+@@ -703,7 +878,15 @@
+ 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,
++ old_areas_cats = old_areas_cats,
++ new_geom = new_geom,
++ new_areas_cats = new_areas_cats)
++
+ return newline
+
+ def FlipLine(self):
+@@ -1510,26 +1693,49 @@
+ return 0
+
+ poList = self._display.GetSelectedIList()
++ cList = poList.contents
++
++ old_geom = self._getGeom(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()
++
+ if add:
+ ret = Vedit_add_vertex(self.poMapInfo, poList,
+- self.poPoints, thresh)
++ self.poPoints, thresh, poNewIds)
+ else:
+ ret = Vedit_remove_vertex(self.poMapInfo, poList,
+- self.poPoints, thresh)
++ self.poPoints, thresh, poNewIds)
++
++ 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 not add and ret > 0 and self._settings['breakLines']:
+ self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
+ None)
+-
++
+ if ret > 0:
+ self._addChangeset()
+-
++
++ if new_id > -1:
++ if add:
++ self.vertexAdded.emit(old_geom = old_geom, new_geom = new_geom)
++ else:
++ self.vertexRemoved.emit(old_geom = old_geom,
++ new_geom = new_geom,
++ old_areas_cats = old_areas_cats,
++ new_areas_cats = new_areas_cats)
++
+ return 1
+
+ def GetLineCats(self, line):
+Index: gui/wxpython/vdigit/toolbars.py
+===================================================================
+--- gui/wxpython/vdigit/toolbars.py (revision 57285)
++++ 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)
+@@ -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
+===================================================================
+--- gui/wxpython/Makefile (revision 57285)
++++ 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)
+
+Index: gui/wxpython/mapdisp/toolbars.py
+===================================================================
+--- gui/wxpython/mapdisp/toolbars.py (revision 57285)
++++ 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 57285)
++++ 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
++ """
++ if self.dialogs['scatt_plot']:
++ self.dialogs['scatt_plot'].Raise()
++ return
++
++ from scatt_plot.dialogs import ScattPlotMainDialog
++ self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface)
++
++ self.dialogs['scatt_plot'].CenterOnScreen()
++ self.dialogs['scatt_plot'].Show()
++
+ def OnVNet(self, event):
+ """!Dialog for v.net* modules
+ """
+Index: lib/vector/vedit/move.c
+===================================================================
+--- lib/vector/vedit/move.c (revision 57285)
++++ 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 57285)
++++ 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 */
+Index: lib/imagery/scatt_sccats.c
+===================================================================
+--- lib/imagery/scatt_sccats.c (revision 0)
++++ lib/imagery/scatt_sccats.c (working copy)
+@@ -0,0 +1,321 @@
++/*!
++ \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_vals, 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_vals->b_conds_arr && cats->type == 1)
++ return -1;
++
++ if(!scatt_vals->scatt_vals_arr && cats->type == 0)
++ 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_vals;
++ ++scatts->n_a_scatts;
++
++ return 0;
++}
++
++int I_sc_remove_scatt_data(struct scCats * cats, struct scdScattData * scatt_vals, 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_vals = 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_vals = 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_vals, int n_vals, int type)
++{
++ scatt_vals->n_vals = n_vals;
++
++ if(type == 0)
++ {
++ scatt_vals->scatt_vals_arr = (unsigned int *) malloc(n_vals * sizeof(unsigned int));
++ memset(scatt_vals->scatt_vals_arr, 0, n_vals * sizeof(unsigned int));
++ scatt_vals->b_conds_arr = NULL;
++ }
++ else if(type == 1)
++ {
++ scatt_vals->b_conds_arr = (unsigned short *) malloc(n_vals * sizeof(unsigned short));
++ memset(scatt_vals->b_conds_arr, 0, n_vals * sizeof(unsigned short));
++ scatt_vals->scatt_vals_arr = NULL;
++ }
++
++ return;
++}
++
++void I_scd_free_scatt_data(struct scdScattData * scatt_vals)
++{
++
++ free(scatt_vals->b_conds_arr);
++ free(scatt_vals->scatt_vals_arr);
++
++ scatt_vals = NULL;
++
++ return;
++}
++
++int I_scd_get_data_size(struct scdScattData * scatt_vals)
++{
++ return scatt_vals->n_vals;
++}
++
++void * I_scd_get_data_ptr(struct scdScattData * scatt_vals)
++{
++ if(!scatt_vals->b_conds_arr)
++ return scatt_vals->b_conds_arr;
++ else if(!scatt_vals->scatt_vals_arr)
++ return scatt_vals->scatt_vals_arr;
++
++ return NULL;
++}
++
++int I_scd_set_value(struct scdScattData * scatt_vals, unsigned int val_idx, unsigned int val)
++{
++ if(val_idx < 0 && val_idx > scatt_vals->n_vals)
++ return -1;
++
++ if(scatt_vals->b_conds_arr)
++ scatt_vals->b_conds_arr[val_idx] = val;
++ else if(scatt_vals->scatt_vals_arr)
++ scatt_vals->scatt_vals_arr[val_idx] = val;
++ else
++ return -1;
++
++ return 0;
++}
+Index: lib/imagery/scatt.c
+===================================================================
+--- lib/imagery/scatt.c (revision 0)
++++ lib/imagery/scatt.c (working copy)
+@@ -0,0 +1,582 @@
++/*!
++ \file lib/imagery/scatt.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>
++
++
++static const int CAT_RAST_SCATT_SEL = 2;
++static const int CAT_RAST_RAST_SEL = 1;
++static const int CAT_RAST_NULL = 0;
++
++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);
++}
++
++int I_create_cat_rast(struct Cell_head * cat_rast_region, const char * cat_rast)
++{
++ FILE * f_cat_rast;
++ char cat_rast_header[1024];//TODO magic number
++ int i_row, i_col;
++ int head_nchars;
++
++ unsigned char * row_data;
++
++ f_cat_rast = fopen(cat_rast, "wb");
++ if(!f_cat_rast)
++ return -1;
++
++ head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
++
++ fwrite(cat_rast_header, sizeof(char), head_nchars/sizeof(char), f_cat_rast);
++ if (ferror(f_cat_rast)){
++ fclose(f_cat_rast);
++ return -1;
++ }
++
++ row_data = (unsigned char *) G_malloc(cat_rast_region->cols * sizeof(unsigned char));
++ for(i_col = 0; i_col < cat_rast_region->cols; i_col++)
++ row_data[i_col] = 0 & 255;
++
++ 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);
++ G_debug(3, "Unable to write into file.");
++ return -1;
++ }
++ }
++
++ fclose(f_cat_rast);
++ return 0;
++}
++
++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,
++ intersec->east, intersec->west, intersec->ns_res, intersec->ew_res);
++}
++
++static int regions_intersecion(struct Cell_head * A, struct Cell_head * B, struct Cell_head * intersec)
++{
++
++ if(B->north < A->south) return -1;
++ else if(B->north > A->north) intersec->north = A->north;
++ else intersec->north = B->north;
++
++ if(B->south > A->north) return -1;
++ else if(B->south < A->south) intersec->south = A->south;
++ else intersec->south = B->south;
++
++ if(B->east < A->west) return -1;
++ else if(B->east > A->east) intersec->east = A->east;
++ else intersec->east = B->east;
++
++ if(B->west > A->east) return -1;
++ else if(B->west < A->west) intersec->west = A->west;
++ else intersec->west = B->west;
++
++ if(intersec->north == intersec->south) return -1;
++
++ if(intersec->east == intersec->west) return -1;
++
++ return 0;
++
++}
++
++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)
++ return -1;
++
++ if(A->ew_res != B->ew_res)
++ return -1;
++
++ ns_res = A->ns_res;
++ ew_res = A->ew_res;
++
++ if(regions_intersecion(A, B, &intersec) == -1)
++ return -1;
++
++ A_bounds->north = ceil((A->north - intersec.north - ns_res * 0.5) / ns_res);
++ A_bounds->south = ceil((A->north - intersec.south - ns_res * 0.5) / ns_res);
++
++ A_bounds->east = ceil((intersec.east - A->west - ew_res * 0.5) / ew_res);
++ A_bounds->west = ceil((intersec.west - A->west - ew_res * 0.5) / ew_res);
++
++ B_bounds->north = ceil((B->north - intersec.north - ns_res * 0.5) / ns_res);
++ B_bounds->south = ceil((B->north - intersec.south - ns_res * 0.5) / ns_res);
++
++ B_bounds->east = ceil((intersec.east - B->west - ew_res * 0.5) / ew_res);
++ B_bounds->west = ceil((intersec.west - B->west - ew_res * 0.5) / ew_res);
++
++ return 0;
++}
++
++
++int I_insert_patch_to_cat_rast(const char * patch_rast, struct Cell_head * cat_rast_region, const char * cat_rast)
++{
++
++ FILE * f_cat_rast;
++ struct Cell_head patch_region, patch_bounds, cat_rast_bounds;
++ char cat_rast_header[1024];//TODO magic number
++ int i_row, i_col, ncols, nrows, cat_rast_col, patch_col, val;
++ int head_nchars;
++ int fd_patch_rast, init_shift, step_shift;
++ unsigned char * patch_data;
++
++ char * null_chunk;
++
++ //TODO G_free mapset (aslo in compute scatts)
++ const char *mapset;
++
++ struct Cell_head patch_lines, cat_rast_lines;
++
++ unsigned char * row_data;
++
++ f_cat_rast = fopen(cat_rast, "rb+");
++ if(!f_cat_rast)
++ return -10;
++
++
++ /* 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;
++ }
++
++ Rast_get_cellhd(patch_rast, mapset, &patch_region);
++ Rast_set_window(&patch_region);
++
++ if ((fd_patch_rast = Rast_open_old(patch_rast, mapset)) < 0) {
++ fclose(f_cat_rast);
++ return -3;
++ }
++
++ null_chunk = Rast_allocate_null_buf();
++
++ if(get_rows_and_cols_bounds(cat_rast_region, &patch_region, &cat_rast_bounds, &patch_bounds) == -1) return -1;
++
++ ncols = cat_rast_bounds.east - cat_rast_bounds.west;
++ nrows = cat_rast_bounds.south - cat_rast_bounds.north;
++
++ patch_data = (unsigned char *) G_malloc(ncols * sizeof(unsigned char));
++
++ init_shift = head_nchars + cat_rast_region->cols * cat_rast_bounds.north + cat_rast_bounds.west;
++
++ if(fseek(f_cat_rast, init_shift, SEEK_SET) != 0) {
++ G_message("seek failed");
++ return -4;
++ }
++
++ 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);
++
++ for(i_col = 0; i_col < ncols; i_col++) {
++ patch_col = patch_bounds.west + i_col;
++
++ if(null_chunk[patch_col] != 1)
++ patch_data[i_col] = 1 & 255;
++ else {
++ patch_data[i_col] = 0 & 255;
++ }
++ }
++
++ fwrite(patch_data, sizeof(unsigned char), (ncols)/sizeof(unsigned char), f_cat_rast);
++ if (ferror(f_cat_rast))
++ {
++ G_free(null_chunk);
++ fclose(f_cat_rast);
++ return -5;
++ }
++ if(fseek(f_cat_rast, step_shift, SEEK_CUR) != 0) {
++ G_message("seek failed");
++ return -6;
++ }
++ }
++
++ Rast_close(fd_patch_rast);
++ G_free(null_chunk);
++ 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)
++{
++ int band_axis_1, band_axis_2, i_scatt, array_idx, cat_idx, i_chunks_pix;
++ int r_bits = 256;
++
++ CELL * band_1_chunks;
++ CELL * band_2_chunks;
++ char * band_1_null_chunks,* band_2_null_chunks;
++
++ int * scatts_bands = scatts->scatts_bands;
++ for(i_scatt = 0; i_scatt < scatts->n_a_scatts; i_scatt++)
++ {
++ band_1_chunks = chunks[scatts_bands[i_scatt * 2]];
++ band_2_chunks = chunks[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]];
++
++ for(i_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
++ {
++ if(!belongs_pix[i_chunks_pix] ||
++ band_1_null_chunks[i_chunks_pix] == 1 ||
++ band_2_null_chunks[i_chunks_pix] == 1)
++ continue;
++
++ array_idx = band_1_chunks[i_chunks_pix] + band_2_chunks[i_chunks_pix] * r_bits;
++
++ ++scatts->scatts_arr[i_scatt]->scatt_vals_arr[array_idx];
++ }
++ }
++}
++
++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)
++{
++
++ int i_chunks_pix, i_cat, i_scatt, n_a_scatts, i_cond;
++ int cat_id, scatt_plts_cat_idx, array_idx;
++ char * band_1_null_chunks,* band_2_null_chunks;
++
++ int r_bits = 256;
++
++ struct scScatts * scatts_conds;
++ struct scScatts * scatt_plts_scatts;
++ struct scdScattData * conds;
++
++ int * scatts_bands;
++ struct scdScattData ** scatts_arr;
++
++ CELL * band_1_chunks;
++ CELL * band_2_chunks;
++ unsigned int * 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));
++
++ for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
++ {
++ scatts_conds = scatt_conds->cats_arr[i_cat];
++
++ cat_id = scatt_conds->cats_ids[i_cat];
++
++ scatt_plts_cat_idx = scatt_plts->cats_idxs[cat_id];
++ if(scatt_plts_cat_idx < 0)
++ continue;
++
++ scatt_plts_scatts = scatt_plts->cats_arr[scatt_plts_cat_idx];
++
++ G_zero(belongs_pix, chunk_size * sizeof(unsigned short));
++
++ if(!scatts_conds->n_a_scatts && !f_cats_rasts_in[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;
++ }
++ }
++ else
++ {
++ scatts_bands = scatts_conds->scatts_bands;
++
++ if(f_cats_rasts_in[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]))
++ {
++ 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++)
++ {
++ if(rast_pixs[i_chunks_pix] != 0 & 255)
++ belongs_pix[i_chunks_pix] = 1;
++ }
++
++ // test every defined conditions in scatter plots
++ for(i_scatt = 0; i_scatt < scatts_conds->n_a_scatts; i_scatt++)
++ {
++ band_1_chunks = chunks[scatts_bands[i_scatt * 2]];
++ band_2_chunks = chunks[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]];
++
++ i_scatt_conds = scatts_conds->scatts_arr[i_scatt]->b_conds_arr;
++
++ for(i_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
++ {
++ if(belongs_pix[i_chunks_pix] ||
++ band_1_null_chunks[i_chunks_pix] == 1 ||
++ band_2_null_chunks[i_chunks_pix] == 1)
++ continue;
++
++ if(i_scatt_conds[band_1_chunks[i_chunks_pix] + band_2_chunks[i_chunks_pix] * r_bits])
++ belongs_pix[i_chunks_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;
++
++ 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;
++ }
++ }
++
++ update_cat_scatt_plt(chunks, null_chunks, chunk_size, belongs_pix, scatt_plts_scatts);
++ }
++
++ G_free(rast_pixs);
++ G_free(belongs_pix);
++
++ return 0;
++}
++
++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
++ int i_cat, i_scatt, cat_id;
++
++ for(i_cat = 0; i_cat < cats->n_a_cats; i_cat++)
++ {
++ for(i_scatt = 0; i_scatt < cats->cats_arr[i_cat]->n_a_scatts; i_scatt++)
++ {
++ G_debug(3, "Active scatt %d in catt %d", i_scatt, i_cat);
++
++ b_needed_bands[cats->cats_arr[i_cat]->scatts_bands[i_scatt * 2]] = 1;
++ b_needed_bands[cats->cats_arr[i_cat]->scatts_bands[i_scatt * 2 + 1]] = 1;
++ }
++ }
++ 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)
++{
++ int i, band_id;
++
++ for(i = 0; i < (* n_a_bands); i++)
++ {
++ 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]);
++ }
++ }
++
++ if(f_cats_rasts_in)
++ for(i = 0; i < n_a_cats; i++)
++ if(f_cats_rasts_in[i])
++ fclose(f_cats_rasts_in[i]);
++
++ if(f_cats_rasts_out)
++ for(i = 0; i < n_a_cats; i++)
++ if(f_cats_rasts_out[i])
++ fclose(f_cats_rasts_out[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)
++{
++ int i_cat, id_cat;
++
++ for(i_cat = 0; i_cat < n_a_cats; i_cat++)
++ {
++ 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;
++ }
++ else
++ f_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)
++{
++ int i_cat, id_cat, head_nchars;
++ char cat_rast_header[1024];//TODO magic number
++
++ head_nchars = get_cat_rast_header(region, cat_rast_header);
++
++ for(i_cat = 0; i_cat < n_a_cats; i_cat++)
++ {
++ if(!f_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;
++ }
++
++ return head_nchars;
++
++}
++
++//TODO change name: I_UpdateScattData???
++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 ||
++ n_bands != scatt_conds->n_bands)
++ return -1;
++
++ const char *mapset;
++
++ FILE * f_cats_rasts_out[scatt_conds->n_a_cats];
++ FILE * f_cats_rasts_in[scatt_conds->n_a_cats];
++
++ CELL * chunks[n_bands];
++ char * null_chunks[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;
++ int fd_bands[n_bands];
++ for(i_band = 0; i_band < n_bands; i_band++)
++ fd_bands[i_band] = -1;
++
++ int bands_ids[n_bands];
++ for(i_band = 0; i_band < n_bands; i_band++)
++ bands_ids[i_band] = -1;
++
++ int b_needed_bands[n_bands];
++ 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]);
++
++ Rast_set_window(region);
++
++ n_a_bands = 0;/*TODO realy needed?*/
++ for(id_band = 0; id_band < n_bands; id_band++)
++ {
++ if(b_needed_bands[id_band])
++ {
++ G_debug(3, "Opening raster no. %d with name: %s", id_band, bands[id_band]);
++
++ /* 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,
++ &bands_ids[0], NULL, NULL, scatt_conds->n_a_cats);
++ return -1;
++ }
++
++ 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,
++ &bands_ids[0], NULL, NULL, scatt_conds->n_a_cats);
++ return -1;
++ }
++
++ //TODO check data type, minimum and maximum value
++ data_type = Rast_get_map_type(fd_bands[n_a_bands]);
++ //if(data_type != CELL)
++ // return -1;
++
++ //What happens if it is not CELL tyoe
++ chunks[id_band] = Rast_allocate_c_buf();
++ null_chunks[id_band] = Rast_allocate_null_buf();
++
++ bands_ids[n_a_bands] = id_band;
++
++ ++n_a_bands;
++ }
++ }
++
++ 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;
++ }
++
++ 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;
++ }
++
++ 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;
++ }
++
++ 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);
++
++ i_chunk = 0;
++
++ nrows = Rast_window_rows();
++ chunk_size = Rast_window_cols();
++
++ for (i_row = 0; i_row < nrows; i_row++)
++ {
++ for(i_band = 0; i_band < n_a_bands; i_band++)
++ {
++ band_id = bands_ids[i_band];
++ G_debug(3, "Reading data for band %d", band_id);
++ Rast_get_c_row(fd_bands[i_band], chunks[band_id], i_row);
++ Rast_get_null_value_row (fd_bands[i_band], null_chunks[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)
++ {
++ 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], &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 0;
++}
+\ No newline at end of file
More information about the grass-commit
mailing list