[GRASS-SVN] r57647 - sandbox/turek/scatter_plot

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Sep 12 08:33:19 PDT 2013


Author: turek
Date: 2013-09-12 08:33:19 -0700 (Thu, 12 Sep 2013)
New Revision: 57647

Modified:
   sandbox/turek/scatter_plot/testing_patch.diff
Log:
scatter plot: \bugs fixing

Modified: sandbox/turek/scatter_plot/testing_patch.diff
===================================================================
--- sandbox/turek/scatter_plot/testing_patch.diff	2013-09-12 12:46:29 UTC (rev 57646)
+++ sandbox/turek/scatter_plot/testing_patch.diff	2013-09-12 15:33:19 UTC (rev 57647)
@@ -1,1232 +1,64 @@
-Index: lib/imagery/scatt.c
+Index: include/imagery.h
 ===================================================================
---- lib/imagery/scatt.c	(revision 0)
-+++ lib/imagery/scatt.c	(working copy)
-@@ -0,0 +1,799 @@
-+/*!
-+   \file lib/imagery/scatt.c
+--- include/imagery.h	(revision 57644)
++++ include/imagery.h	(working copy)
+@@ -135,6 +135,56 @@
+     
+ } IClass_statistics;
+ 
++/* Scatter Plot backend */
 +
-+   \brief Imagery library - functions for wx Scatter Plot Tool.
++#define SC_SCATT_DATA          0 
++#define SC_SCATT_CONDITIONS    1
 +
-+   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 <grass/glocale.h>
-+
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <math.h>
-+#include <string.h>
-+
-+
-+struct rast_row
++/*! Holds list of all catagories. 
++    It can contain selected areas for scatter plots (SC_SCATT_CONDITIONS type) or computed scatter plots (SC_SCATT_DATA type).
++*/
++struct scCats 
 +{
-+    CELL * row;
-+    char * null_row;
-+    struct Range rast_range; /*Range of whole raster.*/
-+};
++    int type;        /*!< SC_SCATT_DATA -> computed scatter plots, SC_SCATT_CONDITIONS -> set conditions for scatter plots to be computed*/
 +
-+/*!
-+   \brief Create pgm header.
-+
-+   Scatter plot internally generates pgm files. These pgms have header in format created by this function.
++    int n_cats;      /*!< number of alocated categories */
 +    
-+   \param region region to be pgm header generated for 
-+   \param [out] header header of pgm file
-+ */
-+static int get_cat_rast_header(struct Cell_head * region, char * header){
-+    return sprintf(header, "P5\n%d\n%d\n1\n", region->cols, region->rows);
-+}
++    int n_bands;     /*!< number of analyzed bands */
++    int n_scatts;    /*!< number of possible scattter plot which can be created from bands */
 +
-+/*!
-+   \brief Create category raster conditions file.
-+    
-+   \param cat_rast_region region to be file generated for
-+   \param cat_rast path of generated category raster file
-+ */
-+int I_create_cat_rast(struct Cell_head * cat_rast_region,  const char * cat_rast)
-+{
-+    FILE * f_cat_rast;
-+    char cat_rast_header[1024];//TODO magic number 
-+    int i_row, i_col;
-+    int head_nchars;
++    int   n_a_cats;  /*!< number of used/active categories */
++    int * cats_ids;  /*!< (cat_idx->cat_id) array index is internal idx (position in cats_arr) and id is saved in it's position*/
++    int * cats_idxs; /*!< (cat_id->cat_idx) array index is id and internal idx is saved in it's position*/
 +
-+    unsigned char * row_data;
++    struct scScatts ** cats_arr; /*!< array of pointers to struct scScatts */
++};
 +
-+    f_cat_rast = fopen(cat_rast, "wb");
-+    if(!f_cat_rast) {
-+        G_warning("Unable to create category raster condition file <%s>.", cat_rast);
-+        return -1;
-+    }
 +
-+    head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
-+
-+    fwrite(cat_rast_header, sizeof(char), head_nchars/sizeof(char), f_cat_rast);
-+    if (ferror(f_cat_rast)){
-+        fclose(f_cat_rast);
-+        G_warning(_("Unable to write header into category raster condition file <%s>."), cat_rast);
-+        return -1;
-+    }
-+
-+    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);
-+        if (ferror(f_cat_rast))
-+        {
-+            fclose(f_cat_rast);
-+            G_warning(_("Unable to write into category raster condition file <%s>."), cat_rast);
-+            return -1;
-+        }
-+    }
-+
-+    fclose(f_cat_rast);
-+    return 0;
-+}
-+
-+static int print_reg(struct Cell_head * intersec, const char * pref, int dbg_level)
-+{
-+    G_debug(dbg_level, "%s:\n n:%f\ns:%f\ne:%f\nw:%f\nns_res:%f\new_res:%f", pref, intersec->north, intersec->south, 
-+               intersec->east, intersec->west, intersec->ns_res, intersec->ew_res);
-+}
-+
-+/*!
-+   \brief Find intersection region of two regions.
-+
-+   \param A pointer to intersected region
-+   \param B pointer to intersected region
-+   \param [out] intersec pointer to intersection region of regions A B (relevant params of the region are: south, north, east, west)
-+
-+   \return  0 if interection exists
-+   \return -1 if regions does not intersect
-+ */
-+static int regions_intersecion(struct Cell_head * A, struct Cell_head * B, struct Cell_head * intersec)
-+{
-+
-+    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;
-+
-+}
-+
-+/*!
-+   \brief Get rows and cols numbers, which defines intersection of the regions.
-+  
-+   \param A pointer to intersected region
-+   \param B pointer to intersected region (A and B must have same resolution)
-+   \param [out] A_bounds rows and cols numbers of A stored in south, north, east, west, which defines intersection of A and B
-+   \param [out] B_bounds rows and cols numbers of B stored in south, north, east, west, which defines intersection of A and B
-+
-+   \return  0 if interection exists
-+   \return -1 if regions do not intersect
-+   \return -2 resolution of regions is not same 
++/*! Holds list of all scatter plots, which belongs to category. 
 +*/
-+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)
++struct scScatts
 +{
-+    float ns_res, ew_res;
-+
-+    struct Cell_head intersec;
-+
-+    /* TODO is it right check? */
-+    if(abs(A->ns_res - B->ns_res) > GRASS_EPSILON) {
-+        G_debug(0, "'get_rows_and_cols_bounds' ns_res does not fit, A->ns_res: %f B->ns_res: %f", A->ns_res, B->ns_res);
-+        return -2;
-+    }
-+
-+    if(abs(A->ew_res - B->ew_res) > GRASS_EPSILON) {
-+        G_debug(0, "'get_rows_and_cols_bounds' ew_res does not fit, A->ew_res: %f B->ew_res: %f", A->ew_res, B->ew_res);
-+        return -2;
-+    }
-+
-+    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;
-+}
-+
-+/*!
-+   \brief Insert raster map patch into pgm file.
-+  
-+   \param patch_rast name of raster map
-+   \param cat_rast_region region of category raster file
-+   \param cat_rast path to category raster file
-+
-+   \return  0 on success
-+   \return -1 on failure
-+*/
-+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, ret;
-+    int fd_patch_rast, init_shift, step_shift;
-+    unsigned char * patch_data;
-+
-+    char * null_chunk_row;
-+
-+    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) {
-+        G_warning(_("Unable to open category raster condtions file <%s>."), cat_rast);
-+        return -1;
-+    }
-+
-+    head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
-+    if ((mapset = G_find_raster(patch_rast,"")) == NULL) {
-+        fclose(f_cat_rast);
-+        G_warning(_("Unable to find patch raster <%s>."), patch_rast);
-+        return -1;
-+    }
-+
-+    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 -1;
-+    }
-+
-+    ret = get_rows_and_cols_bounds(cat_rast_region, &patch_region, &cat_rast_bounds, &patch_bounds);
-+    if(ret == -2) { 
-+        G_warning(_("Resolutions of patch <%s> and patched file <%s> are not same."), patch_rast, cat_rast);
-+
-+        Rast_close(fd_patch_rast);
-+        fclose(f_cat_rast);
-+
-+        return -1;
-+    }
-+    else if (ret == -1){
-+
-+        Rast_close(fd_patch_rast);
-+        fclose(f_cat_rast);
-+
-+        return 0;
-+    }
-+
-+    ncols = cat_rast_bounds.east - cat_rast_bounds.west;
-+    nrows = cat_rast_bounds.south - cat_rast_bounds.north;
-+
-+    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_warning(_("Corrupted  category raster conditions file <%s> (fseek failed)"), cat_rast);
-+
-+        Rast_close(fd_patch_rast);
-+        G_free(null_chunk_row);
-+        fclose(f_cat_rast);
-+
-+        return -1;
-+    }
-+
-+    step_shift = cat_rast_region->cols - ncols;
-+
-+    null_chunk_row =  Rast_allocate_null_buf();
++    int n_a_scatts;     /*!< number of used/active scatter plots*/
 +    
-+    for(i_row = 0; i_row < nrows; i_row++) {
-+        Rast_get_null_value_row (fd_patch_rast, null_chunk_row, i_row + patch_bounds.north);
++    int * scatts_bands; /*!< array of bands for which represents the scatter plots, 
++                             every scatter plot has assigned two bads (size of array is n_a_scatts * 2)*/
++    int * scatt_idxs;   /*!< (scatt_id->scatt_idx) internal idx of the scatter plot (position in scatts_arr)*/
 +
-+        for(i_col = 0; i_col < ncols; i_col++) {
-+            patch_col = patch_bounds.west + i_col;
++    struct scdScattData ** scatts_arr; /*!< array of pointers to scdScattData */
++};
 +
-+            if(null_chunk_row[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_warning(_("Unable to write into category raster conditions file <%s>"), cat_rast);
-+            
-+            Rast_close(fd_patch_rast);
-+            G_free(null_chunk_row);
-+            fclose(f_cat_rast);
-+
-+            return -1;
-+        }
-+        if(fseek(f_cat_rast, step_shift, SEEK_CUR) != 0) {
-+            G_warning(_("Corrupted  category raster conditions file <%s> (fseek failed)"), cat_rast);
-+            
-+            Rast_close(fd_patch_rast);
-+            G_free(null_chunk_row);
-+            fclose(f_cat_rast);
-+            
-+            return -1;
-+        }
-+    }
-+
-+    Rast_close(fd_patch_rast);
-+    G_free(null_chunk_row);
-+    fclose(f_cat_rast);
-+    return 0;
-+}
-+
-+/*!
-+   \brief Updates scatter plots data in category by pixels which meets category conditions.
-+  
-+   \param bands_rows data represents data describig one row from raster band
-+   \param belongs_pix array which defines which pixels belongs to category (1 value) and which not (0 value)
-+   \param [out] scatts pointer to scScatts struct of type SC_SCATT_DATA, which are modified according to values in belongs_pix
++/*! Holds scatter plot data.
 +*/
-+static inline void update_cat_scatt_plts(struct rast_row * bands_rows, unsigned short * belongs_pix, struct scScatts * scatts)
++struct scdScattData
 +{
-+    int band_axis_1, band_axis_2, i_scatt, array_idx, cat_idx, i_chunk_rows_pix, max_arr_idx;
++    int n_vals; /*!< Number of values in scatter plot. */
 +
-+    CELL * b_1_row;
-+    CELL * b_2_row;
-+    char * b_1_null_row,* b_2_null_row;
-+    struct rast_row b_1_rast_row, b_2_rast_row;
++    unsigned char  * b_conds_arr; /*!< array of selected areas (used for SC_SCATT_CONDITIONS type) otherwise NULL */
++    unsigned int  * scatt_vals_arr; /*!< array of computed areas (used for SC_SCATT_DATA type) otherwise NULL */
++};
 +
-+    struct Range b_1_range, b_2_range;
-+    int b_1_range_size;
 +
-+    int row_size = Rast_window_cols();
-+
-+    int * scatts_bands = scatts->scatts_bands;
-+
-+    for(i_scatt = 0; i_scatt < scatts->n_a_scatts; i_scatt++)
-+    {   
-+        b_1_rast_row = bands_rows[scatts_bands[i_scatt * 2]];
-+        b_2_rast_row = bands_rows[scatts_bands[i_scatt * 2 + 1]];
-+
-+        b_1_row = b_1_rast_row.row;
-+        b_2_row = b_2_rast_row.row;
-+
-+        b_1_null_row =  b_1_rast_row.null_row;
-+        b_2_null_row =  b_2_rast_row.null_row;
-+
-+        b_1_range = b_1_rast_row.rast_range;
-+        b_2_range = b_2_rast_row.rast_range;
-+        
-+        b_1_range_size = b_1_range.max - b_1_range.min + 1;
-+        max_arr_idx = (b_1_range.max -  b_1_range.min + 1) * (b_2_range.max -  b_2_range.min + 1);
-+
-+        for(i_chunk_rows_pix = 0; i_chunk_rows_pix < row_size; i_chunk_rows_pix++)
-+        {
-+            /* pixel does not belongs to scatter plot or has null value in one of the bands */
-+            if(!belongs_pix[i_chunk_rows_pix] || 
-+                b_1_null_row[i_chunk_rows_pix] == 1 || 
-+                b_2_null_row[i_chunk_rows_pix] == 1)                
-+                continue;
-+
-+            /* index in scatter plot array */
-+            array_idx = b_1_row[i_chunk_rows_pix] - b_1_range.min + (b_2_row[i_chunk_rows_pix] - b_2_range.min) * b_1_range_size;
-+
-+            if(array_idx < 0 || array_idx >= max_arr_idx) {
-+                        G_warning ("Data inconsistent. Value computed for scatter plot is out of initialized range.");
-+                continue;
-+            }
-+
-+            /* increment scatter plot value */
-+            ++scatts->scatts_arr[i_scatt]->scatt_vals_arr[array_idx];
-+        }
-+    }
-+}
-+
-+/*!
-+   \brief Computes scatter plots data from chunk_rows.
-+
-+   \param scatts pointer to scScatts struct of type SC_SCATT_DATA, where are computed scatter plots stored
-+   \param scatt_conds pointer to scScatts struct of type SC_SCATT_CONDITIONS, where are selected areas (condtitions)stored
-+
-+   \param chunk_rows data arrays of chunk_rows from analyzed raster bands (all data in chunk_rows, null_chunk_rows and belongs_pix arrays represents same region)
-+   \param null_chunk_rows null data arrays of chunk_rows from analyzed raster bands
-+   \param row_size size of data in chunk_rows, null_chunk_rows and belongs_pix arrays
-+   \param f_cats_rasts_conds file which stores selected areas (conditions) from mapwindow see I_create_cat_rast() and I_pa
-+   \param fd_cats_rasts array of openedraster maps which represents all selected pixels for category
-+   \param region analysis region
-+
-+   \return  0 on success
-+   \return -1 on failure
-+*/
-+static inline int compute_scatts_from_chunk_row(struct Cell_head *region, struct scCats * scatt_conds, 
-+                                                FILE ** f_cats_rasts_conds, struct rast_row * bands_rows, 
-+                                                struct scCats * scatts, int * fd_cats_rasts)
-+{
-+
-+    int i_rows_pix, i_cat, i_scatt, n_a_scatts, n_pixs;
-+    int cat_id, scatt_plts_cat_idx, array_idx, max_arr_idx;
-+    char * b_1_null_row,* b_2_null_row;
-+    struct rast_row b_1_rast_row, b_2_rast_row;
-+    CELL * cat_rast_row;
-+
-+    struct scScatts * scatts_conds;
-+    struct scScatts * scatts_scatt_plts;
-+    struct scdScattData * conds;
-+
-+    struct Range b_1_range, b_2_range;
-+    int b_1_range_size;
-+
-+    int * scatts_bands;
-+    struct scdScattData ** scatts_arr;
-+
-+    CELL * b_1_row;
-+    CELL * b_2_row;
-+    unsigned char * i_scatt_conds;
-+
-+    int row_size = Rast_window_cols();
-+
-+    unsigned short * belongs_pix = (unsigned short *) G_malloc(row_size * sizeof(unsigned short)); 
-+    unsigned char * rast_pixs = (unsigned char *) G_malloc(row_size * sizeof(unsigned char));
-+    cat_rast_row =  Rast_allocate_c_buf();
-+
-+     
-+    for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
-+    {
-+        scatts_conds = scatt_conds->cats_arr[i_cat];
-+
-+        cat_id = scatt_conds->cats_ids[i_cat];
-+
-+        scatt_plts_cat_idx = scatts->cats_idxs[cat_id];
-+        if(scatt_plts_cat_idx < 0)
-+            continue;
-+        scatts_scatt_plts = scatts->cats_arr[scatt_plts_cat_idx];
-+
-+        G_zero(belongs_pix, row_size * sizeof(unsigned short));
-+
-+        /* if category has no conditions defined, scatter plots without any constraint are computed (default scatter plots) */
-+        if(!scatts_conds->n_a_scatts && !f_cats_rasts_conds[i_cat]) {
-+            for(i_scatt = 0; i_scatt < scatts_scatt_plts->n_a_scatts; i_scatt++)
-+            {       
-+                /* all pixels belongs */
-+                for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)                
-+                    belongs_pix[i_rows_pix] = 1;
-+            }
-+        }
-+        /* compute belonging pixels for defined conditions */
-+        else
-+        {
-+            scatts_bands = scatts_conds->scatts_bands;
-+
-+            /* check conditions from category raster condtitions file */
-+            if(f_cats_rasts_conds[i_cat]) {
-+                n_pixs = fread(rast_pixs, sizeof(unsigned char), (row_size)/sizeof(unsigned char), f_cats_rasts_conds[i_cat]);
-+
-+                if (ferror(f_cats_rasts_conds[i_cat]))
-+                {
-+                    G_free(rast_pixs);
-+                    G_free(belongs_pix);
-+                    G_warning(_("Unable to read from category raster condtition file."));
-+                    return -1;
-+                }
-+                if (n_pixs != n_pixs) {
-+                    G_free(rast_pixs);
-+                    G_free(belongs_pix);
-+                    G_warning(_("Invalid size of category raster conditions file."));
-+                    return -1;
-+
-+                }
-+
-+                for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)
-+                {
-+                    if(rast_pixs[i_rows_pix] != 0 & 255)
-+                        belongs_pix[i_rows_pix] = 1;
-+                }
-+            }
-+
-+            /* check condtions defined in scatter plots*/
-+            for(i_scatt = 0; i_scatt < scatts_conds->n_a_scatts; i_scatt++)
-+            {   
-+                b_1_rast_row = bands_rows[scatts_bands[i_scatt * 2]];
-+                b_2_rast_row = bands_rows[scatts_bands[i_scatt * 2 + 1]];
-+
-+                b_1_row = b_1_rast_row.row;
-+                b_2_row = b_2_rast_row.row;
-+
-+                b_1_null_row =  b_1_rast_row.null_row;
-+                b_2_null_row =  b_2_rast_row.null_row;
-+
-+                b_1_range = b_1_rast_row.rast_range;
-+                b_2_range = b_2_rast_row.rast_range;
-+
-+                b_1_range_size = b_1_range.max - b_1_range.min + 1;
-+                max_arr_idx = (b_1_range.max -  b_1_range.min + 1) * (b_2_range.max -  b_2_range.min + 1);
-+
-+                i_scatt_conds = scatts_conds->scatts_arr[i_scatt]->b_conds_arr;
-+
-+                for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)
-+                {
-+                    /* pixels already belongs to category from category raster conditions file or contains null value in one of the bands */
-+                    if(belongs_pix[i_rows_pix] || 
-+                       b_1_null_row[i_rows_pix] == 1 || 
-+                       b_2_null_row[i_rows_pix] == 1)
-+                        continue;
-+
-+                    array_idx = b_1_row[i_rows_pix] - b_1_range.min + (b_2_row[i_rows_pix] - b_2_range.min) * b_1_range_size;
-+                    if(array_idx < 0 || array_idx >= max_arr_idx) {
-+                        G_warning ("Data inconsistent. Value computed for scatter plot is out of initialized range.");
-+                        continue;
-+                    }
-+                    /* pixels meets condtion defined in scatter plot */
-+                    if(i_scatt_conds[array_idx])
-+                        belongs_pix[i_rows_pix] = 1;
-+                }                
-+            }
-+        }
-+
-+        /* update category raster with belonging pixels */
-+        if(fd_cats_rasts[i_cat] >= 0) {
-+            Rast_set_null_value(cat_rast_row, Rast_window_cols(), CELL_TYPE); 
-+
-+            for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)
-+                if(belongs_pix[i_rows_pix])
-+                    cat_rast_row[i_rows_pix] = belongs_pix[i_rows_pix];
-+
-+            Rast_put_c_row (fd_cats_rasts[i_cat], cat_rast_row); 
-+        }
-+
-+        /* update scatter plots with belonging pixels */
-+        update_cat_scatt_plts(bands_rows, belongs_pix, scatts_scatt_plts);
-+    }
-+
-+    G_free(cat_rast_row);
-+    G_free(rast_pixs);
-+    G_free(belongs_pix);
-+
-+    return 0;
-+}
-+
-+/*!
-+   \brief Get list if bands needed to be opened for analysis from scCats struct.
-+*/
-+static void get_needed_bands(struct scCats * cats, int * b_needed_bands)
-+{
-+    // results in b_needed_bands - array of bools - if item has value 1, band (defined by item index) is needed to be opened
-+    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;
-+}
-+
-+/*!
-+   \brief Helper function for clean up.
-+*/
-+static void free_compute_scatts_data(int * fd_bands, struct rast_row * bands_rows, int n_a_bands, int * bands_ids, 
-+                                     int * fd_cats_rasts, FILE ** f_cats_rasts_conds, int n_a_cats)
-+{
-+    int i, band_id;
-+
-+    for(i = 0; i < n_a_bands; i++)
-+    {   
-+        band_id = bands_ids[i];
-+        if(band_id >= 0) {
-+            Rast_close(fd_bands[i]);
-+            G_free(bands_rows[band_id].row);
-+            G_free(bands_rows[band_id].null_row);
-+        }
-+    }
-+     
-+    if(f_cats_rasts_conds)
-+        for(i = 0; i < n_a_cats; i++)
-+            if(f_cats_rasts_conds[i])
-+                fclose(f_cats_rasts_conds[i]);
-+
-+    if(fd_cats_rasts)
-+        for(i = 0; i < n_a_cats; i++)
-+            if(fd_cats_rasts[i] >= 0)
-+                Rast_close(fd_cats_rasts[i]);
-+
-+}
-+
-+/*!
-+   \brief Compute scatter plots data.
-+
-+    If category has not defined no category raster condition file and no scatter plot with consdtion,
-+    default scatter plot is computed.
-+
-+   \param region analysis region, beaware that all input data must be prepared for this region (bands (their ranges), cats_rasts_conds rasters...)
-+   \param region function calls Rast_set_window for this region
-+   \param scatt_conds pointer to scScatts struct of type SC_SCATT_CONDITIONS, where are stored selected areas (conditions) in scatter plots
-+   \param cats_rasts_conds paths to category raster conditions files representing selected areas (conditions) in rasters for every category 
-+   \param cats_rasts_conds index in array represents corresponding category id
-+   \param cats_rasts_conds for manupulation with category raster conditions file see also I_id_scatt_to_bands() and I_insert_patch_to_cat_rast()
-+   \param bands names of analyzed bands, order of bands is defined by their id
-+   \param n_bands number of bands
-+   \param [out] scatts pointer to scScatts struct of type SC_SCATT_DATA, where are computed scatter plots stored
-+   \param [out] cats_rasts array of raster maps names where will be stored all selected pixels for every category
-+
-+   \return  0 on success
-+   \return -1 on failure
-+*/
-+int I_compute_scatts(struct Cell_head *region, struct scCats * scatt_conds, const char ** cats_rasts_conds,
-+                     const char ** bands, int n_bands, struct scCats * scatts, const char ** cats_rasts) 
-+{
-+    const char *mapset;
-+    char header[1024];
-+
-+    int fd_cats_rasts[scatt_conds->n_a_cats];
-+    FILE * f_cats_rasts_conds[scatt_conds->n_a_cats];
-+
-+    struct rast_row bands_rows[n_bands];
-+
-+    RASTER_MAP_TYPE data_type;
-+
-+    int nrows, i_band, n_a_bands, band_id, 
-+        i, i_row, head_nchars, i_cat, id_cat;
-+   
-+    int fd_bands[n_bands];
-+    int bands_ids[n_bands];
-+    int b_needed_bands[n_bands];  
-+
-+    Rast_set_window(region);
-+
-+    for(i_band = 0; i_band < n_bands; i_band++)
-+        fd_bands[i_band] = -1;
-+    
-+    for(i_band = 0; i_band < n_bands; i_band++)
-+        bands_ids[i_band] = -1;
-+
-+    if (n_bands != scatts->n_bands ||
-+        n_bands != scatt_conds->n_bands)
-+        return -1;
-+
-+    memset(b_needed_bands, 0, (size_t)n_bands * sizeof(int));
-+
-+    get_needed_bands(scatt_conds, &b_needed_bands[0]);
-+    get_needed_bands(scatts, &b_needed_bands[0]);
-+
-+    n_a_bands = 0;
-+
-+    /* open band rasters, which are needed for computation */
-+    for(band_id = 0; band_id < n_bands; band_id++)
-+    {
-+        if(b_needed_bands[band_id])
-+        {
-+            G_debug(3, "Opening raster no. %d with name: %s", band_id, bands[band_id]);
-+
-+            if ((mapset = G_find_raster2(bands[band_id],"")) == NULL) {
-+                free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, 
-+                                         bands_ids, NULL, NULL, scatt_conds->n_a_cats);
-+                G_warning(_("Unbale to read find raster <%s>"), bands[band_id]);
-+                return -1;
-+            }
-+            
-+            if ((fd_bands[n_a_bands] = Rast_open_old(bands[band_id], mapset)) < 0) {
-+                free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, 
-+                                         bands_ids, NULL, NULL, scatt_conds->n_a_cats);
-+                G_warning(_("Unbale to open raster <%s>"), bands[band_id]);
-+                return -1;
-+            }
-+
-+            data_type = Rast_get_map_type(fd_bands[n_a_bands]);
-+            if(data_type != CELL_TYPE) {
-+                G_warning(_("Raster <%s> type is not <%s>"), bands[band_id], "CELL");
-+                return -1;
-+            }
-+
-+            bands_rows[band_id].row =  Rast_allocate_c_buf();
-+            bands_rows[band_id].null_row =  Rast_allocate_null_buf();
-+
-+            if(Rast_read_range(bands[band_id], mapset, &bands_rows[band_id].rast_range) != 1){
-+                free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, 
-+                                         bands_ids, NULL, NULL, scatt_conds->n_a_cats);
-+                G_warning(_("Unable to read range of raster <%s>"), bands[band_id]);
-+                return -1;
-+            }      
-+
-+            bands_ids[n_a_bands] = band_id;
-+            ++n_a_bands;
-+        }
-+    }
-+
-+    /* open category rasters condition files and category rasters */
-+    for(i_cat = 0; i_cat < scatts->n_a_cats; i_cat++)
-+    {
-+        id_cat = scatts->cats_ids[i_cat];
-+        if(cats_rasts[id_cat]) {
-+            fd_cats_rasts[i_cat] = Rast_open_new(cats_rasts[id_cat], CELL_TYPE);   
-+        }
-+        else
-+            fd_cats_rasts[i_cat] = -1;
-+
-+        if(cats_rasts_conds[id_cat]) {
-+            f_cats_rasts_conds[i_cat] = fopen(cats_rasts_conds[id_cat], "r");
-+            if(!f_cats_rasts_conds[i_cat]) {
-+                free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, bands_ids, 
-+                                         f_cats_rasts_conds, f_cats_rasts_conds, scatt_conds->n_a_cats);
-+                G_warning(_("Unable to open category raster condtition file <%s>"), bands[band_id]);
-+                return -1;
-+            }
-+        }
-+        else
-+            f_cats_rasts_conds[i_cat] = NULL;
-+    }
-+
-+    head_nchars =  get_cat_rast_header(region, header);
-+    for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
-+        if(f_cats_rasts_conds[i_cat])
-+            if( fseek(f_cats_rasts_conds[i_cat] , head_nchars, SEEK_SET) != 0) {
-+                G_warning(_("Corrupted category raster conditions file (fseek failed)"));
-+                return -1;
-+            }
-+
-+    nrows = Rast_window_rows();
-+
-+    /* analyze bands by rows */
-+    for (i_row = 0; i_row < nrows; i_row++)
-+    {
-+        for(i_band = 0; i_band < n_a_bands; i_band++)
-+        {   
-+            band_id = bands_ids[i_band];
-+            Rast_get_c_row(fd_bands[i_band], bands_rows[band_id].row, i_row);
-+            Rast_get_null_value_row (fd_bands[i_band], bands_rows[band_id].null_row, i_row);
-+        }
-+        if(compute_scatts_from_chunk_row(region, scatt_conds, f_cats_rasts_conds, bands_rows, scatts, fd_cats_rasts) == -1) 
-+        {
-+            free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, bands_ids, fd_cats_rasts, 
-+                                     f_cats_rasts_conds, scatt_conds->n_a_cats);
-+            return -1;
-+        }
-+ 
-+    }
-+    free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, bands_ids, 
-+                             fd_cats_rasts, f_cats_rasts_conds, scatt_conds->n_a_cats); 
-+    return 0;    
-+}
-+
-+
-+int I_merge_arrays(unsigned char *  merged_arr, unsigned char *  overlay_arr, unsigned rows, unsigned cols, double alpha)
-+{
-+    unsigned int i_row, i_col, i_b;
-+    unsigned int row_idx, col_idx, idx;
-+    unsigned int c_a_i, c_a;
-+
-+    for(i_row = 0; i_row < rows; i_row++)
-+    {
-+        row_idx = i_row * cols;
-+        for(i_col = 0; i_col < cols; i_col++)
-+        {
-+                col_idx = 4 * (row_idx + i_col);
-+                idx = col_idx + 3;
-+
-+                c_a = overlay_arr[idx] * alpha;
-+                c_a_i = 255 - c_a;
-+
-+                merged_arr[idx] = (c_a_i * (int)merged_arr[idx] + c_a * 255) / 255;
-+                
-+                for(i_b = 0; i_b < 3; i_b++)
-+                {
-+                    idx = col_idx + i_b;
-+                    merged_arr[idx] = (c_a_i * (int)merged_arr[idx] + c_a * (int)overlay_arr[idx]) / 255;
-+                }
-+        }
-+    }
-+    return 0; 
-+}
-+
-+
-+int I_apply_colormap(unsigned char * vals, unsigned char * vals_mask, unsigned vals_size, unsigned char * colmap, unsigned char * col_vals){
-+    unsigned int i_val;
-+    int v, i, i_cm;
-+
-+    for(i_val = 0; i_val < vals_size; i_val++){
-+        i_cm = 4 * i_val;
-+
-+        v = vals[i_val];
-+
-+        if(vals_mask[i_val])
-+            for(i = 0; i < 4; i++) col_vals[i_cm + i] = colmap[258 * 4 + i];
-+        else if(v > 255)
-+            for(i = 0; i < 4; i++) col_vals[i_cm + i] = colmap[257 * 4 + i];
-+        else if(v < 0)
-+            for(i = 0; i < 4; i++) col_vals[i_cm + i] = colmap[256 * 4 + i];
-+        else
-+            for(i = 0; i < 4; i++){ col_vals[i_cm + i] = colmap[v * 4 + i];
-+        }
-+    }
-+    return 0;
-+}
-Index: lib/imagery/scatt_sccats.c
-===================================================================
---- lib/imagery/scatt_sccats.c	(revision 0)
-+++ lib/imagery/scatt_sccats.c	(working copy)
-@@ -0,0 +1,405 @@
-+/*!
-+   \file lib/imagery/scatt_cat_rast.c
-+
-+   \brief Imagery library - functions for manipulation with scatter plot structs.
-+
-+   Copyright (C) 2013 by the GRASS Development Team
-+
-+   This program is free software under the GNU General Public License
-+   (>=v2).  Read the file COPYING that comes with GRASS for details.
-+
-+   \author Stepan Turek <stepan.turek at seznam.cz> (Mentor: Martin Landa)
-+ */
-+
-+#include <grass/raster.h>
-+#include <grass/imagery.h>
-+#include <grass/gis.h>
-+
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <math.h>
-+#include <string.h>
-+
-+/*!
-+   \brief Compute band ids from scatter plot id.
-+
-+    Scatter plot id describes which bands defines the scatter plot.
-+
-+    Let say we have 3 bands, their ids are 0, 1 and 2.
-+    Scatter plot with id 0 consists of band 1 (b_1_id) 0 and  band 2 (b_2_id) 1.
-+    All scatter plots:
-+    scatt_id b_1_id b_2_id
-+    0        0      1
-+    1        0      2
-+    2        1      2
-+
-+   \param scatt_id scatter plot id
-+   \param n_bands number of bands
-+   \param [out] b_1_id id of band1
-+   \param[out] b_2_id id of band2
-+
-+   \return 0
-+ */
-+int I_id_scatt_to_bands(const int scatt_id, const int n_bands, int * b_1_id, int * b_2_id)
-+{   
-+    int n_b1 = n_bands - 1;
-+
-+    * b_1_id = (int) ((2 * n_b1 + 1 - sqrt((double)((2 * n_b1 + 1) * (2 * n_b1 + 1) - 8 * scatt_id))) / 2);
-+
-+    * b_2_id = scatt_id - ((* b_1_id) * (2 * n_b1 + 1) - (* b_1_id) * (* b_1_id)) / 2 + (* b_1_id) + 1;
-+
-+    return 0;
-+}
-+
-+
-+/*!
-+   \brief Compute scatter plot id from band ids.
-+
-+    See also I_id_scatt_to_bands().
-+
-+   \param n_bands number of bands
-+   \param b_1_id id of band1
-+   \param b_1_id id of band2
-+   \param [out] scatt_id scatter plot id
-+
-+   \return 0
-+ */
-+int I_bands_to_id_scatt(const int b_1_id, const int b_2_id, const int n_bands, int * scatt_id)
-+{   
-+    int n_b1 = n_bands - 1;
-+
-+    * scatt_id = (b_1_id * (2 * n_b1 + 1) - b_1_id * b_1_id) / 2 + b_2_id - b_1_id - 1;
-+
-+    return 0;
-+}
-+
-+/*!
-+   \brief Initialize structure for storing scatter plots data.
-+
-+   \param cats pointer to scCats struct 
-+   \param n_bands number of bands
-+   \param type SC_SCATT_DATA - stores scatter plots 
-+   \param type SC_SCATT_CONDITIONS - stores selected areas in scatter plots
-+ */
-+void I_sc_init_cats(struct scCats * cats, int n_bands, int type)
-+{
-+    int i_cat;
-+
-+    cats->type = type;
-+
-+    cats->n_cats = 100;
-+    cats->n_a_cats = 0;
-+
-+    cats->n_bands = n_bands;
-+    cats->n_scatts = (n_bands - 1) * n_bands / 2;
-+
-+    cats->cats_arr = (struct scScatts **) G_malloc(cats->n_cats * sizeof(struct scScatts *));
-+    memset(cats->cats_arr, 0, cats-> n_cats * sizeof(struct scScatts *));
-+
-+    cats->cats_ids = (int *)  G_malloc(cats->n_cats * sizeof(int));
-+    cats->cats_idxs =(int *)  G_malloc(cats->n_cats * sizeof(int));
-+
-+    for(i_cat = 0; i_cat < cats->n_cats; i_cat++)
-+        cats->cats_idxs[i_cat] = -1;
-+
-+    return;
-+}
-+
-+/*!
-+   \brief Free data of struct scCats, the structure itself remains alocated.
-+
-+   \param cats pointer to existing scCats struct
-+ */
-+void I_sc_free_cats(struct scCats * cats)
-+{
-+    int i_cat;
-+
-+    for(i_cat = 0; i_cat < cats->n_a_cats; i_cat++)
-+    {        
-+        if(cats->cats_arr[i_cat])
-+        {   
-+            G_free(cats->cats_arr[i_cat]->scatt_idxs);
-+            G_free(cats->cats_arr[i_cat]->scatts_bands);
-+            G_free(cats->cats_arr[i_cat]->scatts_arr);
-+            G_free(cats->cats_arr[i_cat]);
-+        }
-+    }
-+
-+    G_free(cats->cats_ids);
-+    G_free(cats->cats_idxs);
-+    G_free(cats->cats_arr);
-+
-+    cats->n_cats = 0;
-+    cats->n_a_cats = 0;
-+    cats->n_bands = 0;
-+    cats->n_scatts = 0;
-+    cats->type = -1;
-+
-+    return;
-+}
-+
-+#if 0
-+void I_sc_get_active_categories(int * a_cats_ids, int * n_a_cats, struct scCats * cats)
-+{
-+    a_cats_ids = cats->cats_ids;
-+    * n_a_cats = cats->n_a_cats;
-+}
-+#endif
-+
-+/*!
-+   \brief Add category.
-+    
-+    Category represents group of scatter plots.
-+
-+   \param cats pointer to scCats struct
-+
-+   \return assigned category id (starts with 0)
-+   \return -1 if maximum nuber of categories was reached
-+ */
-+int I_sc_add_cat(struct scCats * cats)
-+{
-+    int i_scatt, i_cat_id, cat_id;
-+    int n_a_cats = cats->n_a_cats;
-+
-+    if(cats->n_a_cats >= cats->n_cats)
-+        return -1;
-+
-+    for(i_cat_id = 0; i_cat_id < cats->n_cats; i_cat_id++)
-+        if(cats->cats_idxs[i_cat_id] < 0) {
-+            cat_id = i_cat_id;
-+            break;
-+        }
-+
-+    cats->cats_ids[n_a_cats] = cat_id;
-+    cats->cats_idxs[cat_id] = n_a_cats;
-+    
-+    cats->cats_arr[n_a_cats] = (struct scScatts *) G_malloc(sizeof(struct scScatts));
-+
-+    cats->cats_arr[n_a_cats]->scatts_arr = (struct scdScattData **) G_malloc(cats->n_scatts * sizeof(struct scdScattData *));
-+    memset((cats->cats_arr[n_a_cats]->scatts_arr), 0, cats->n_scatts * sizeof(struct scdScattData *));
-+    
-+    cats->cats_arr[n_a_cats]->n_a_scatts = 0;
-+
-+    cats->cats_arr[n_a_cats]->scatts_bands = (int *) G_malloc(cats->n_scatts * 2 * sizeof(int));
-+     
-+    cats->cats_arr[n_a_cats]->scatt_idxs = (int *) G_malloc(cats->n_scatts * sizeof(int));
-+    for(i_scatt = 0; i_scatt < cats->n_scatts; i_scatt++)
-+        cats->cats_arr[n_a_cats]->scatt_idxs[i_scatt] = -1;
-+    
-+    ++cats->n_a_cats;
-+
-+    return cat_id;
-+}
-+
-+#if 0
-+int I_sc_delete_cat(struct scCats * cats, int cat_id)
-+{
-+    int cat_idx, i_cat;
-+
-+    if(cat_id < 0 || cat_id >= cats->n_cats)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+
-+    G_free(cats->cats_arr[cat_idx]->scatt_idxs);
-+    G_free(cats->cats_arr[cat_idx]->scatts_bands);
-+    G_free(cats->cats_arr[cat_idx]->scatts_arr);
-+    G_free(cats->cats_arr[cat_idx]);
-+
-+    for(i_cat = cat_idx; i_cat < cats->n_a_cats - 1; i_cat++)
-+    {
-+        cats->cats_arr[i_cat] = cats->cats_arr[i_cat + 1];
-+        cats->cats_ids[i_cat] = cats->cats_ids[i_cat + 1];
-+    }
-+    cats->cats_idxs[cat_id] = -1; 
-+
-+    --cats->n_a_cats;
-+    
-+    return 0;
-+}
-+#endif
-+
-+/*!
-+   \brief Insert scatter plot data .
-+    Inserted scatt_data struct must have same type as cats struct (SC_SCATT_DATA or SC_SCATT_CONDITIONS).
-+
-+   \param cats pointer to scCats struct
-+   \param cat_id id number of category.
-+   \param scatt_id id number of scatter plot.
-+
-+   \return  0 on success
-+   \return -1 on failure
-+ */
-+int I_sc_insert_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
-+{
-+    int band_1, band_2, cat_idx, n_a_scatts;
-+    struct scScatts * scatts;
-+
-+    if(cat_id < 0 || cat_id >= cats->n_cats)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+
-+    if(scatt_id < 0 && scatt_id >= cats->n_scatts)
-+        return -1;
-+
-+    scatts = cats->cats_arr[cat_idx];
-+    if(scatts->scatt_idxs[scatt_id] >= 0)
-+        return -1;
-+
-+    if(!scatt_data->b_conds_arr && cats->type == SC_SCATT_CONDITIONS)
-+        return -1;
-+
-+    if(!scatt_data->scatt_vals_arr && cats->type == SC_SCATT_DATA)
-+        return -1;
-+
-+    n_a_scatts = scatts->n_a_scatts;
-+
-+    scatts->scatt_idxs[scatt_id] = n_a_scatts;
-+
-+    I_id_scatt_to_bands(scatt_id, cats->n_bands, &band_1, &band_2);
-+
-+    scatts->scatts_bands[n_a_scatts * 2] = band_1;
-+    scatts->scatts_bands[n_a_scatts * 2 + 1] = band_2;
-+
-+    scatts->scatts_arr[n_a_scatts] = scatt_data;
-+    ++scatts->n_a_scatts;
-+
-+    return 0;
-+}
-+
-+#if 0
-+int I_sc_remove_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
-+{
-+    int cat_idx, scatt_idx, n_init_scatts, i_scatt;
-+    struct scScatts * scatts;
-+
-+    if(cat_id < 0 && cat_id >= cats->n_cats)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+
-+    if(scatt_id < 0 || scatt_id >= cats->n_scatts)
-+        return -1;
-+
-+    scatts = cats->cats_arr[cat_idx];
-+    if(scatts->scatt_idxs[scatt_id] < 0)
-+        return -1;
-+
-+    scatt_data = scatts->scatts_arr[scatt_idx];
-+
-+    for(i_scatt = scatt_idx; i_scatt < scatts->n_a_scatts - 1; i_scatt++)
-+    {
-+        scatts->scatts_arr[i_scatt] = scatts->scatts_arr[i_scatt + 1];
-+        scatts->scatts_bands[i_scatt * 2] = scatts->scatts_bands[(i_scatt + 1)* 2];
-+        scatts->scatts_bands[i_scatt * 2 + 1] = scatts->scatts_bands[(i_scatt + 1) * 2 + 1];
-+    }
-+    scatts->scatts_arr[scatts->n_a_scatts] = NULL;
-+
-+    scatts->scatt_idxs[scatt_id] = -1;
-+
-+    scatt_data = scatts->scatts_arr[scatt_id];
-+    scatts->n_a_scatts--;
-+
-+    return 0;
-+}
-+
-+int I_sc_set_value(struct scCats * cats, int cat_id, int scatt_id, int value_idx, int value)
-+{
-+    int n_a_scatts = cats->cats_arr[cat_id]->n_a_scatts;
-+    int cat_idx, scatt_idx, ret;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+    
-+    if(cats->cats_arr[cat_idx]->scatt_idxs[scatt_id] < 0)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    scatt_idx = cats->cats_arr[cat_idx]->scatt_idxs[scatt_id];
-+
-+    I_scd_set_value(cats->cats_arr[cat_idx]->scatts_arr[scatt_idx], value_idx, value);
-+
-+    return 0;
-+}
-+#endif
-+
-+/*!
-+   \brief Insert scatter plot data.
-+    
-+   \param scatt_data pointer to existing struct scdScattData
-+   \param type SC_SCATT_DATA for scatter plots or SC_SCATT_CONDITIONS for selected areas in scatter plot
-+   \param n_vals number of data values
-+   \param data array of values (unsigned char for SC_SCATT_CONDITIONS, unsigned int for SC_SCATT_DATA)
-+ */
-+void I_scd_init_scatt_data(struct scdScattData * scatt_data, int type, int n_vals, void * data)
-+{
-+    scatt_data->n_vals = n_vals;
-+
-+    if(type == SC_SCATT_DATA)
-+    {   
-+        if(data)
-+            scatt_data->scatt_vals_arr = (unsigned int *) data;
-+        else {
-+            scatt_data->scatt_vals_arr = (unsigned int *) G_malloc(n_vals * sizeof(unsigned int));
-+            memset(scatt_data->scatt_vals_arr, 0, n_vals * sizeof(unsigned int)); 
-+        }
-+        scatt_data->b_conds_arr = NULL;
-+    }
-+    else if(type == SC_SCATT_CONDITIONS)
-+    {
-+        if(data)
-+            scatt_data->b_conds_arr = (unsigned char *) data;
-+        else {
-+            scatt_data->b_conds_arr = (unsigned char *) G_malloc(n_vals * sizeof(unsigned char));
-+            memset(scatt_data->b_conds_arr, 0, n_vals * sizeof(unsigned char));
-+        }
-+        scatt_data->scatt_vals_arr = NULL;
-+    }
-+
-+    return;
-+}
-+
-+
-+#if 0
-+void I_scd_get_range_min_max(struct scdScattData * scatt_data, CELL * band_1_min, CELL * band_1_max, CELL * band_2_min, CELL * band_2_max)
-+{
-+
-+    Rast_get_range_min_max(&(scatt_data->band_1_range), band_1_min, band_2_min);
-+    Rast_get_range_min_max(&(scatt_data->band_2_range), band_2_min, band_2_max);
-+
-+    return;
-+}
-+s
-+void * I_scd_get_data_ptr(struct scdScattData * scatt_data)
-+{
-+    if(!scatt_data->b_conds_arr)
-+        return scatt_data->b_conds_arr;
-+    else if(!scatt_data->scatt_vals_arr)
-+        return scatt_data->scatt_vals_arr;
-+
-+    return NULL;
-+}
-+
-+int I_scd_set_value(struct scdScattData * scatt_data, unsigned int val_idx, unsigned int val)
-+{
-+    if(val_idx < 0 && val_idx >  scatt_data->n_vals)
-+        return -1;
-+
-+    if(scatt_data->b_conds_arr)
-+        scatt_data->b_conds_arr[val_idx] = val;
-+    else if(scatt_data->scatt_vals_arr)
-+        scatt_data->scatt_vals_arr[val_idx] = val;
-+    else
-+        return -1;
-+
-+    return 0;
-+}
-+#endif
-Index: lib/vector/Vlib/open.c
-===================================================================
---- lib/vector/Vlib/open.c	(revision 57644)
-+++ lib/vector/Vlib/open.c	(working copy)
-@@ -240,7 +240,9 @@
-         }
-         else {
-             char file_path[GPATH_MAX];
--            
-+            /* reduce to current mapset if search path was set */
-+            if(strcmp(Map->mapset, "") == 0)
-+                Map->mapset = G_store(G_mapset());
-             /* temporary map: reduce to current mapset if search path
-              * was set */
-             if (strcmp(Map->mapset, "") == 0)
+ #define SIGNATURE_TYPE_MIXED 1
+ 
+ #define GROUPFILE "CURGROUP"
 Index: include/defs/vedit.h
 ===================================================================
 --- include/defs/vedit.h	(revision 57644)
@@ -1271,67 +103,6 @@
  /* sig.c */
  int I_init_signatures(struct Signature *, int);
  int I_new_signature(struct Signature *);
-Index: include/imagery.h
-===================================================================
---- include/imagery.h	(revision 57644)
-+++ include/imagery.h	(working copy)
-@@ -135,6 +135,56 @@
-     
- } IClass_statistics;
- 
-+/* Scatter Plot backend */
-+
-+#define SC_SCATT_DATA          0 
-+#define SC_SCATT_CONDITIONS    1
-+
-+
-+/*! Holds list of all catagories. 
-+    It can contain selected areas for scatter plots (SC_SCATT_CONDITIONS type) or computed scatter plots (SC_SCATT_DATA type).
-+*/
-+struct scCats 
-+{
-+    int type;        /*!< SC_SCATT_DATA -> computed scatter plots, SC_SCATT_CONDITIONS -> set conditions for scatter plots to be computed*/
-+
-+    int n_cats;      /*!< number of alocated categories */
-+    
-+    int n_bands;     /*!< number of analyzed bands */
-+    int n_scatts;    /*!< number of possible scattter plot which can be created from bands */
-+
-+    int   n_a_cats;  /*!< number of used/active categories */
-+    int * cats_ids;  /*!< (cat_idx->cat_id) array index is internal idx (position in cats_arr) and id is saved in it's position*/
-+    int * cats_idxs; /*!< (cat_id->cat_idx) array index is id and internal idx is saved in it's position*/
-+
-+    struct scScatts ** cats_arr; /*!< array of pointers to struct scScatts */
-+};
-+
-+
-+/*! Holds list of all scatter plots, which belongs to category. 
-+*/
-+struct scScatts
-+{
-+    int n_a_scatts;     /*!< number of used/active scatter plots*/
-+    
-+    int * scatts_bands; /*!< array of bands for which represents the scatter plots, 
-+                             every scatter plot has assigned two bads (size of array is n_a_scatts * 2)*/
-+    int * scatt_idxs;   /*!< (scatt_id->scatt_idx) internal idx of the scatter plot (position in scatts_arr)*/
-+
-+    struct scdScattData ** scatts_arr; /*!< array of pointers to scdScattData */
-+};
-+
-+/*! Holds scatter plot data.
-+*/
-+struct scdScattData
-+{
-+    int n_vals; /*!< Number of values in scatter plot. */
-+
-+    unsigned char  * b_conds_arr; /*!< array of selected areas (used for SC_SCATT_CONDITIONS type) otherwise NULL */
-+    unsigned int  * scatt_vals_arr; /*!< array of computed areas (used for SC_SCATT_DATA type) otherwise NULL */
-+};
-+
-+
- #define SIGNATURE_TYPE_MIXED 1
- 
- #define GROUPFILE "CURGROUP"
 Index: gui/icons/grass/polygon.png
 ===================================================================
 Cannot display: file marked as a binary type.
@@ -1896,6 +667,105 @@
          return True
  
      def StopEditing(self):
+Index: gui/wxpython/vnet/dialogs.py
+===================================================================
+--- gui/wxpython/vnet/dialogs.py	(revision 57644)
++++ gui/wxpython/vnet/dialogs.py	(working copy)
+@@ -1218,7 +1218,7 @@
+                       pos = (row, 1))
+ 
+         row += 1
+-        gridSizer.Add(item = self.settings["invert_colors"], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
++        gridSizer.Add(item=self.settings["invert_colors"], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+ 
+         gridSizer.AddGrowableCol(1)
+         styleBoxSizer.Add(item = gridSizer, flag = wx.EXPAND)
+Index: gui/wxpython/vnet/toolbars.py
+===================================================================
+--- gui/wxpython/vnet/toolbars.py	(revision 57644)
++++ gui/wxpython/vnet/toolbars.py	(working copy)
+@@ -19,9 +19,9 @@
+ 
+ import wx
+ 
+-from icon              import MetaIcon
++from icons.icon import MetaIcon
+ from gui_core.toolbars import BaseToolbar, BaseIcons
+-from core.gcmd         import RunCommand
++from core.gcmd import RunCommand
+ from core.utils import _
+ 
+ class PointListToolbar(BaseToolbar):
+Index: gui/wxpython/Makefile
+===================================================================
+--- gui/wxpython/Makefile	(revision 57644)
++++ gui/wxpython/Makefile	(working copy)
+@@ -13,7 +13,7 @@
+ 	$(wildcard animation/* core/*.py dbmgr/* gcp/*.py gmodeler/* \
+ 	gui_core/*.py iclass/* lmgr/*.py location_wizard/*.py mapwin/*.py mapdisp/*.py \
+ 	mapswipe/* modules/*.py nviz/*.py psmap/* rlisetup/* timeline/* 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,8 +21,9 @@
+ 
+ PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,animation core dbmgr gcp gmodeler \
+ 	gui_core iclass lmgr location_wizard mapwin mapdisp modules nviz psmap \
+-	mapswipe vdigit wxplot web_services rlisetup vnet timeline)
++	mapswipe vdigit wxplot web_services rlisetup vnet timeline scatt_plot)
+ 
++
+ DSTDIRS := $(patsubst %,$(ETCDIR)/%,icons scripts xml)
+ 
+ default: $(DSTFILES)
+Index: gui/wxpython/mapdisp/toolbars.py
+===================================================================
+--- gui/wxpython/mapdisp/toolbars.py	(revision 57644)
++++ gui/wxpython/mapdisp/toolbars.py	(working copy)
+@@ -239,7 +239,8 @@
+                       (MapIcons["scatter"],     self.parent.OnScatterplot),
+                       (MapIcons["histogram"],   self.parent.OnHistogramPyPlot),
+                       (BaseIcons["histogramD"], self.parent.OnHistogram),
+-                      (MapIcons["vnet"],        self.parent.OnVNet)))
++                      (MapIcons["vnet"],        self.parent.OnVNet),
++                      (MapIcons["scatter"],     self.parent.OnScatterplot2)))
+         
+     def OnDecoration(self, event):
+         """!Decorations overlay menu
+Index: gui/wxpython/mapdisp/frame.py
+===================================================================
+--- gui/wxpython/mapdisp/frame.py	(revision 57644)
++++ gui/wxpython/mapdisp/frame.py	(working copy)
+@@ -225,6 +225,7 @@
+         #
+         self.dialogs = {}
+         self.dialogs['attributes'] = None
++        self.dialogs['scatt_plot'] = None
+         self.dialogs['category'] = None
+         self.dialogs['barscale'] = None
+         self.dialogs['legend'] = None
+@@ -1168,6 +1169,19 @@
+         """!Returns toolbar with zooming tools"""
+         return self.toolbars['map']
+ 
++    def OnScatterplot2(self, event):
++        """!Init interactive scatterplot tools
++        """
++        if self.dialogs['scatt_plot']:
++            self.dialogs['scatt_plot'].Raise()
++            return
++
++        from scatt_plot.dialogs import ScattPlotMainDialog
++        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface)
++        
++        self.dialogs['scatt_plot'].CenterOnScreen()
++        self.dialogs['scatt_plot'].Show()
++
+     def OnVNet(self, event):
+         """!Dialog for v.net* modules 
+         """
 Index: gui/wxpython/iclass/dialogs.py
 ===================================================================
 --- gui/wxpython/iclass/dialogs.py	(revision 57644)
@@ -2364,52 +1234,855 @@
      def DrawCoincidencePlots(self):
          """!Draw coincidence plots"""
          for bandIdx in range(len(self.bandList)):
-Index: gui/wxpython/mapdisp/toolbars.py
+Index: gui/wxpython/scatt_plot/core_c.py
 ===================================================================
---- gui/wxpython/mapdisp/toolbars.py	(revision 57644)
-+++ gui/wxpython/mapdisp/toolbars.py	(working copy)
-@@ -239,7 +239,8 @@
-                       (MapIcons["scatter"],     self.parent.OnScatterplot),
-                       (MapIcons["histogram"],   self.parent.OnHistogramPyPlot),
-                       (BaseIcons["histogramD"], self.parent.OnHistogram),
--                      (MapIcons["vnet"],        self.parent.OnVNet)))
-+                      (MapIcons["vnet"],        self.parent.OnVNet),
-+                      (MapIcons["scatter"],     self.parent.OnScatterplot2)))
-         
-     def OnDecoration(self, event):
-         """!Decorations overlay menu
-Index: gui/wxpython/mapdisp/frame.py
+--- gui/wxpython/scatt_plot/core_c.py	(revision 0)
++++ gui/wxpython/scatt_plot/core_c.py	(working copy)
+@@ -0,0 +1,203 @@
++"""!
++ 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)
++"""
++
++#TODO just for testing
++import time
++
++import sys
++from multiprocessing import Process, Queue
++
++from ctypes import *
++try:
++    from grass.lib.imagery import *
++    from grass.lib.gis import Cell_head, G_get_window
++except ImportError, e:
++    sys.stderr.write(_("Loading ctypes libs failed"))
++
++from core.gcmd import GException
++
++def ApplyColormap(vals, vals_mask, colmap, out_vals):
++    
++    c_uint8_p = POINTER(c_uint8)
++    c_double_p = POINTER(c_double)
++
++
++    vals_p = vals.ctypes.data_as(c_uint8_p)
++    vals_mask_p = vals_mask.ctypes.data_as(c_uint8_p)
++    colmap_p = colmap.ctypes.data_as(c_uint8_p)
++    out_vals_p = out_vals.ctypes.data_as(c_uint8_p)
++
++    vals_size = vals.reshape((-1)).shape[0]
++    I_apply_colormap(vals_p, vals_mask_p, vals_size, colmap_p, out_vals_p)
++
++def MergeArrays(merged_arr, overlay_arr, alpha):
++    if merged_arr.shape != overlay_arr.shape:
++        GException("MergeArrays: merged_arr.shape != overlay_arr.shape")
++
++    c_uint8_p = POINTER(c_uint8)
++    merged_p = merged_arr.ctypes.data_as(c_uint8_p)
++    overlay_p = overlay_arr.ctypes.data_as(c_uint8_p)
++
++    I_merge_arrays(merged_p, overlay_p, merged_arr.shape[0], merged_arr.shape[1], alpha)
++
++def MergeArrays(merged_arr, overlay_arr, alpha):
++    if merged_arr.shape != overlay_arr.shape:
++        GException("MergeArrays: merged_arr.shape != overlay_arr.shape")
++
++    c_uint8_p = POINTER(c_uint8)
++    merged_p = merged_arr.ctypes.data_as(c_uint8_p)
++    overlay_p = overlay_arr.ctypes.data_as(c_uint8_p)
++
++    I_merge_arrays(merged_p, overlay_p, merged_arr.shape[0], merged_arr.shape[1], alpha)
++
++def ComputeScatts(region, scatt_conds, bands, n_bands, scatts, cats_rasts_conds, cats_rasts):
++
++    q = Queue()
++    p = Process(target=_computeScattsProcess, args=(region, scatt_conds, bands, 
++                                                    n_bands, scatts, cats_rasts_conds, cats_rasts, q))
++    p.start()
++    ret = q.get()
++    p.join()
++    
++    return ret[0], ret[1]
++
++def UpdateCatRast(patch_rast, region, cat_rast):
++    q = Queue()
++    p = Process(target=_updateCatRastProcess, args=(patch_rast, region, cat_rast, q))
++    p.start()
++    ret = q.get()
++    p.join()
++
++    return ret
++
++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_conds, cats_rasts, output_queue):
++
++    #TODO names for types not 0 and 1?
++    sccats_c, cats_rasts_c, refs = _getComputationStruct(scatts, cats_rasts, SC_SCATT_DATA, n_bands)
++    scatt_conds_c, cats_rasts_conds_c, refs2 = _getComputationStruct(scatt_conds, cats_rasts_conds, SC_SCATT_CONDITIONS, n_bands)
++
++    char_bands = _stringListToCharArr(bands)
++   
++    cell_head = _regionToCellHead(region)
++
++    ret = I_compute_scatts(pointer(cell_head),
++                           pointer(scatt_conds_c),
++                           pointer(cats_rasts_conds_c),
++                           pointer(char_bands),
++                           n_bands,
++                           pointer(sccats_c),
++                           pointer(cats_rasts_c))
++
++    I_sc_free_cats(pointer(sccats_c))
++    I_sc_free_cats(pointer(scatt_conds_c))
++
++    output_queue.put((ret, scatts))
++
++def _getBandcRange( band_info):
++    band_c_range = struct_Range()
++
++    band_c_range.max = band_info['max']
++    band_c_range.min = band_info['min']
++
++    return band_c_range
++
++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_rasts, cats_type, n_bands):
++
++    sccats = struct_scCats()
++    I_sc_init_cats(pointer(sccats), c_int(n_bands), c_int(cats_type));
++
++    refs = []        
++    cats_rasts_core = []
++    
++    for cat_id, scatt_ids in cats.iteritems():
++        cat_c_id = I_sc_add_cat(pointer(sccats))
++        cats_rasts_core.append(cats_rasts[cat_id])
++
++        for scatt_id, dt in scatt_ids.iteritems():
++            # if key is missing condition is always True (full scatter plor is computed)
++                vals = dt['np_vals']
++
++                scatt_vals = scdScattData()
++
++                c_void_p = ctypes.POINTER(ctypes.c_void_p)
++
++                if cats_type == SC_SCATT_DATA:
++                    vals[:] = 0
++                elif cats_type == SC_SCATT_CONDITIONS:
++                    pass
++                else:
++                    return None
++                data_p = vals.ctypes.data_as(c_void_p)
++                I_scd_init_scatt_data(pointer(scatt_vals), cats_type, len(vals), data_p)
++
++                refs.append(scatt_vals)
++
++                I_sc_insert_scatt_data(pointer(sccats),  
++                                       pointer(scatt_vals),
++                                       cat_c_id, scatt_id)
++
++    cats_rasts_c = _stringListToCharArr(cats_rasts_core)
++
++    return sccats, cats_rasts_c, refs
++
++def _updateCatRastProcess(patch_rast, region, cat_rast, output_queue):
++    cell_head = _regionToCellHead(region)
++    
++    
++    ret = I_insert_patch_to_cat_rast(patch_rast, 
++                                     pointer(cell_head), 
++                                     cat_rast)
++
++    output_queue.put(ret)
++
++
+Index: gui/wxpython/scatt_plot/frame.py
 ===================================================================
---- gui/wxpython/mapdisp/frame.py	(revision 57644)
-+++ gui/wxpython/mapdisp/frame.py	(working copy)
-@@ -225,6 +225,7 @@
-         #
-         self.dialogs = {}
-         self.dialogs['attributes'] = None
-+        self.dialogs['scatt_plot'] = None
-         self.dialogs['category'] = None
-         self.dialogs['barscale'] = None
-         self.dialogs['legend'] = None
-@@ -1168,6 +1169,19 @@
-         """!Returns toolbar with zooming tools"""
-         return self.toolbars['map']
- 
-+    def OnScatterplot2(self, event):
-+        """!Init interactive scatterplot tools
-+        """
-+        if self.dialogs['scatt_plot']:
-+            self.dialogs['scatt_plot'].Raise()
+--- gui/wxpython/scatt_plot/frame.py	(revision 0)
++++ gui/wxpython/scatt_plot/frame.py	(working copy)
+@@ -0,0 +1,636 @@
++"""!
++ at package scatt_plot.dialogs
++
++ at brief GUI.
++
++Classes:
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++import os
++import sys
++
++import wx
++import wx.lib.scrolledpanel as scrolled
++import wx.lib.mixins.listctrl as listmix
++
++from core import globalvar
++from core.gcmd import GException, GError, RunCommand
++
++from gui_core.gselect import Select
++from gui_core.dialogs import SetOpacityDialog
++
++from scatt_plot.controllers import ScattsManager
++from scatt_plot.toolbars import MainToolbar, EditingToolbar
++from scatt_plot.scatt_core import idScattToidBands
++from scatt_plot.plots import ScatterPlotWidget
++from vnet.dialogs import VnetStatusbar
++
++try:
++    from agw import aui
++except ImportError:
++    import wx.lib.agw.aui as aui
++
++class IClassScatterPlotsPanel(wx.Panel):
++    def __init__(self, parent, giface, iclass_mapwin = None,
++                 id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
++
++        #wx.SplitterWindow.__init__(self, parent = parent, id = id,
++        #                           style = wx.SP_LIVE_UPDATE)
++        wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
++
++        #self.head_panel = wx.Panel(parent = self, id = wx.ID_ANY)
++        self.scatt_mgr = ScattsManager(guiparent = self, giface = giface, iclass_mapwin = iclass_mapwin)
++
++        # toobars
++        self.toolbars = {}
++        self.toolbars['mainToolbar'] = MainToolbar(parent = self, scatt_mgr = self.scatt_mgr)
++        self.toolbars['editingToolbar'] = EditingToolbar(parent = self, scatt_mgr = self.scatt_mgr)
++        
++        self._createCategoryPanel(self)
++
++        self.plot_panel = IClassPlotPanel(self, self.scatt_mgr)
++
++        # statusbar
++        self.stPriors = {'high' : 5, 'info' : 1}
++        self.stBar = VnetStatusbar(parent = self, style = 0)
++        self.stBar.SetFieldsCount(number = 1)
++
++        mainsizer = wx.BoxSizer(wx.VERTICAL)
++        mainsizer.Add(item = self.toolbars['mainToolbar'], proportion = 0, flag = wx.EXPAND)
++        mainsizer.Add(item = self.toolbars['editingToolbar'], proportion = 0, flag = wx.EXPAND)
++        mainsizer.Add(item = self.catsPanel, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT , border = 5)
++        mainsizer.Add(item = self.plot_panel, proportion = 1, flag = wx.EXPAND)
++        mainsizer.Add(item = self.stBar, proportion = 0)
++
++        self.catsPanel.Hide()
++        self.toolbars['editingToolbar'].Hide()
++
++        self.SetSizer(mainsizer)
++        
++        self.scatt_mgr.cursorPlotMove.connect(self.CursorPlotMove)
++        self.scatt_mgr.renderingStarted.connect(lambda : self.stBar.AddStatusItem(text=_("Rendering..."), 
++                                                                                 key='comp', 
++                                                                                 priority=self.stPriors['high']))
++        self.scatt_mgr.renderingFinished.connect(lambda : self.stBar.RemoveStatusItem(key='comp'))
++
++        self.scatt_mgr.computingStarted.connect(lambda : self.stBar.AddStatusItem(text=_("Computing data..."), 
++                                                                                 key='comp', 
++                                                                                 priority=self.stPriors['high']))
++
++        #self.SetSashGravity(0.5)
++        #self.SplitHorizontally(self.head_panel, self.plot_panel, -50)
++        self.Layout()
++
++    def CursorPlotMove(self, x, y):
++
++        x = int(round(x))
++        y = int(round(y))
++        self.stBar.AddStatusItem(text="%d; %d" % (x, y), 
++                                 key='coords', 
++                                 priority=self.stPriors['info'])
++
++
++    def NewScatterPlot(self, scatt_id, transpose):
++        return self.plot_panel.NewScatterPlot(scatt_id, transpose)
++
++    def ShowPlotEditingToolbar(self, show):
++        self.toolbars["editingToolbar"].Show(show)
++        self.Layout()
++
++    def ShowCategoryPanel(self, show):
++        self.catsPanel.Show(show)
++        
++        #if show:
++        #    self.SetSashSize(5) 
++        #else:
++        #    self.SetSashSize(0)
++        self.plot_panel.SetVirtualSize(self.plot_panel.GetBestVirtualSize())
++        self.Layout()
++
++    def _createCategoryPanel(self, parent):
++        self.catsPanel = wx.Panel(parent = parent)
++        self.cats_list = CategoryListCtrl(parent = self.catsPanel, 
++                                          cats_mgr = self.scatt_mgr.GetCategoriesManager())
++
++        self.catsPanel.SetMaxSize((-1, 150))
++
++        box_capt = wx.StaticBox(parent = self.catsPanel, id = wx.ID_ANY,
++                             label = ' %s ' % _("Classes manager for scatter plots"))
++        catsSizer = wx.StaticBoxSizer(box_capt, wx.VERTICAL)
++
++        catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND | wx.ALL)
++        self.catsPanel.SetSizer(catsSizer)
++
++
++class IClassPlotPanel(scrolled.ScrolledPanel):
++    def __init__(self, parent, scatt_mgr, id = wx.ID_ANY):
++    
++        scrolled.ScrolledPanel.__init__(self, parent)
++        self.SetupScrolling(scroll_x = False, scroll_y = True, scrollToTop = False)
++
++        self.scatt_mgr = scatt_mgr
++
++        self.mainPanel = wx.Panel(parent = self, id = wx.ID_ANY)
++
++        #self._createCategoryPanel()
++        # Fancy gui
++        self._mgr = aui.AuiManager(self.mainPanel)
++        #self._mgr.SetManagedWindow(self)
++
++        self._mgr.Update()
++
++        self._doLayout()
++        self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
++        self.Bind(wx.EVT_SCROLL_CHANGED, self.OnScrollChanged)
++
++        self.Bind(aui.EVT_AUI_PANE_CLOSE, self.OnPlotPaneClosed)
++
++        dlgSize = (-1, 400)
++        #self.SetBestSize(dlgSize)
++        #self.SetInitialSize(dlgSize)
++        self.SetAutoLayout(1)
++        #fix goutput's pane size (required for Mac OSX)
++        #if self.gwindow:         
++        #    self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
++        self.ignore_scroll = 0
++        self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
++
++        self.scatt_i = 1
++        self.scatt_id_scatt_i = {}
++
++    def ScatterPlotClosed(self, scatt_id):
++
++        scatt_i = self.scatt_id_scatt_i[scatt_id]
++
++        name = self._getScatterPlotName(scatt_i)
++        pane = self._mgr.GetPane(name)
++
++        if pane.IsOk(): 
++          self._mgr.ClosePane(pane) 
++        self._mgr.Update() 
++
++    def OnMouseWheel(self, event):
++        #TODO very ugly find some better solution        
++        self.ignore_scroll = 3
++        event.Skip()
++
++    def ScrollChildIntoView(self, child):
++        #For aui manager it does not work and returns position always to the top -> deactivated.
++        pass
++
++    def OnPlotPaneClosed(self, event):
++        if isinstance(event.pane.window, ScatterPlotWidget):
++            event.pane.window.CleanUp()
++
++    def OnScrollChanged(self, event):
++        wx.CallAfter(self.Layout)
++
++    def OnScroll(self, event):
++        if self.ignore_scroll > 0:
++            self.ignore_scroll -= 1
++        else:
++            event.Skip()
++
++        #wx.CallAfter(self._mgr.Update)
++        #wx.CallAfter(self.Layout)
++
++    def _doLayout(self):
++
++        mainsizer = wx.BoxSizer(wx.VERTICAL)
++        mainsizer.Add(item = self.mainPanel, proportion = 1, flag = wx.EXPAND)
++        self.SetSizer(mainsizer)
++
++        self.Layout()
++        self.SetupScrolling()
++
++    def OnCloseDialog(self, event):
++        """!Close dialog"""
++        self.scatt_mgr.CleanUp()
++        self.Destroy()
++
++    def OnSettings(self, event):
++        pass
++
++    def _newScatterPlotName(self, scatt_id):
++        name = self._getScatterPlotName(self.scatt_i) 
++        self.scatt_id_scatt_i[scatt_id] = self.scatt_i
++        self.scatt_i += 1
++        return name
++
++    def _getScatterPlotName(self, i):
++        name = "scatter plot %d" % i
++        return name
++
++    def NewScatterPlot(self, scatt_id, transpose):
++        #TODO needs to be resolved (should be in this class)
++
++        scatt = ScatterPlotWidget(parent = self.mainPanel, 
++                                  scatt_mgr = self.scatt_mgr, 
++                                  scatt_id = scatt_id, 
++                                  transpose = transpose)
++        scatt.plotClosed.connect(self.ScatterPlotClosed)
++
++        bands = self.scatt_mgr.GetBands()
++
++        #TODO too low level
++        b1_id, b2_id = idScattToidBands(scatt_id, len(bands))
++
++        x_b =  bands[b1_id].split('@')[0]
++        y_b = bands[b2_id].split('@')[0]
++
++        if transpose:
++            tmp = x_b
++            x_b = y_b
++            y_b = tmp
++
++        caption = "%s x: %s y: %s" % (_("scatter plot"), x_b, y_b)
++
++        self._mgr.AddPane(scatt,
++                           aui.AuiPaneInfo().Dockable(True).Floatable(True).
++                           Name(self._newScatterPlotName(scatt_id)).MinSize((-1, 300)).
++                           Caption(caption).
++                           Center().Position(1).MaximizeButton(True).
++                           MinimizeButton(True).CaptionVisible(True).
++                           CloseButton(True).Layer(0))
++
++        self._mgr.Update()
++  
++        self.SetVirtualSize(self.GetBestVirtualSize())
++        self.Layout()
++
++        return scatt
++
++    def GetScattMgr(self):
++        return  self.scatt_mgr
++
++class CategoryListCtrl(wx.ListCtrl,
++                       listmix.ListCtrlAutoWidthMixin,
++                       listmix.TextEditMixin):
++
++    def __init__(self, parent, cats_mgr, id = wx.ID_ANY):
++
++        wx.ListCtrl.__init__(self, parent, id,
++                             style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES)
++        self.columns = ((_('Class name'), 'name'),
++                        (_('Color'), 'color'))
++        self.Populate(columns = self.columns)
++        
++        self.cats_mgr = cats_mgr
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++
++        self.rightClickedItemIdx = wx.NOT_FOUND
++        
++        listmix.ListCtrlAutoWidthMixin.__init__(self)
++
++        listmix.TextEditMixin.__init__(self)
++      
++        self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnCategoryRightUp) #wxMSW
++        self.Bind(wx.EVT_RIGHT_UP,            self.OnCategoryRightUp) #wxGTK
++
++        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)
 +
-+        from scatt_plot.dialogs import ScattPlotMainDialog
-+        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface)
++            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()))
 +        
-+        self.dialogs['scatt_plot'].CenterOnScreen()
-+        self.dialogs['scatt_plot'].Show()
++    def OnSel(self, event): 
++        event.Skip()
 +
-     def OnVNet(self, event):
-         """!Dialog for v.net* modules 
-         """
++    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
++
++    def OnCategoryRightUp(self, event):
++        """!Show context menu on right click"""
++        item, flags = self.HitTest((event.GetX(), event.GetY()))
++        if item != wx.NOT_FOUND and flags & wx.LIST_HITTEST_ONITEM:
++            self.rightClickedItemIdx = item
++
++        # generate popup-menu
++        cat_idx = self.rightClickedItemIdx
++
++        cats = self.cats_mgr.GetCategories()
++        cat_id = cats[cat_idx]
++        showed = self.cats_mgr.GetCategoryAttrs(cat_id)['show']
++        
++        menu = wx.Menu()
++
++        if showed:
++            text = _("Hide")
++        else:
++            text = _("Show")
++
++        item_id = wx.NewId()
++        menu.Append(item_id, text = text)
++        self.Bind(wx.EVT_MENU, lambda event : self._setCatAttrs(cat_id=cat_id,
++                                                                attrs={'show' : not showed}), 
++                                                                id=item_id) 
++        menu.AppendSeparator()
++        
++        if cat_idx != 0:
++            item_id = wx.NewId()
++            menu.Append(item_id, text=_("Move category up"))
++            self.Bind(wx.EVT_MENU, self.OnMoveUp, id=item_id)
++
++        if cat_idx != len(cats) - 1:
++            item_id = wx.NewId()
++            menu.Append(item_id, text=_("Move category down"))
++            self.Bind(wx.EVT_MENU, self.OnMoveDown, id=item_id)
++
++        menu.AppendSeparator()
++        
++        item_id = wx.NewId()
++        menu.Append(item_id, text=_("Change opacity level"))
++        self.Bind(wx.EVT_MENU, self.OnPopupOpacityLevel, id=item_id)
++
++        item_id = wx.NewId()
++        menu.Append(item_id, text=_("Export raster"))
++        self.Bind(wx.EVT_MENU, self.OnExportCatRast, id=item_id)
++
++
++        self.PopupMenu(menu)
++        menu.Destroy()
++
++    def OnExportCatRast(self, event):
++        """!Export training areas"""
++        #TODO
++        #   GMessage(parent=self, message=_("No class raster to export."))
++        #    return
++
++        cat_idx = self.rightClickedItemIdx
++        cat_id = self.cats_mgr.GetCategories()[cat_idx]
++
++        self.cats_mgr.ExportCatRast(cat_id)
++
++    def OnMoveUp(self, event):
++        cat_idx = self.rightClickedItemIdx
++        cat_id = self.cats_mgr.GetCategories()[cat_idx]
++        self.cats_mgr.ChangePosition(cat_id, cat_idx - 1)
++        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++
++    def OnMoveDown(self, event):
++        cat_idx = self.rightClickedItemIdx
++        cat_id = self.cats_mgr.GetCategories()[cat_idx]
++        self.cats_mgr.ChangePosition(cat_id, cat_idx + 1)
++        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++
++    def OnPopupOpacityLevel(self, event):
++        """!Popup opacity level indicator"""
++
++        cat_id = self.cats_mgr.GetCategories()[self.rightClickedItemIdx]
++        cat_attrs = self.cats_mgr.GetCategoryAttrs(cat_id)
++        value = cat_attrs['opacity'] * 100
++        name = cat_attrs['name']
++
++        dlg = SetOpacityDialog(self, opacity = value,
++                               title = _("Change opacity of class <%s>" % name))
++
++        dlg.applyOpacity.connect(lambda value:
++                                 self._setCatAttrs(cat_id=cat_id, attrs={'opacity' : value}))
++        dlg.CentreOnParent()
++
++        if dlg.ShowModal() == wx.ID_OK:
++            self._setCatAttrs(cat_id=cat_id, attrs={'opacity' : value})
++        
++        dlg.Destroy()
++
++    def _setCatAttrs(self, cat_id, attrs):
++        self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
++        self.cats_mgr.SetCategoryAttrs(cat_id, attrs)
++        self.cats_mgr.setCategoryAttrs.connect(self.Update)
++
++
++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 = _("x axis:"))
++
++        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 = _("y axis:"))
++
++        self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
++                                     choices = self.bands,
++                                     style = wx.CB_READONLY, size = (350, 30))
++
++        # buttons
++        self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
++        
++        self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
++
++        self._layout()
++
++    def _layout(self):
++
++        border = wx.BoxSizer(wx.VERTICAL) 
++        dialogSizer = wx.BoxSizer(wx.VERTICAL)
++
++        regionSizer = wx.BoxSizer(wx.HORIZONTAL)
++
++        dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label, 
++                                                    sel = self.band_1_ch))
++
++        dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label, 
++                                                    sel = self.band_2_ch))
++
++        # buttons
++        self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
++
++        self.btnsizer.Add(item = self.btn_close, proportion = 0,
++                          flag = wx.ALL | wx.ALIGN_CENTER,
++                          border = 10)
++        
++        self.btnsizer.Add(item = self.btn_ok, proportion = 0,
++                          flag = wx.ALL | wx.ALIGN_CENTER,
++                          border = 10)
++
++        dialogSizer.Add(item = self.btnsizer, proportion = 0,
++                        flag = wx.ALIGN_CENTER)
++
++        border.Add(item = dialogSizer, proportion = 0,
++                   flag = wx.ALL, border = 5)
++
++        self.SetSizer(border)
++        self.Layout()
++        self.Fit()
++
++        # bindings
++        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
++        self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
++
++    def _addSelectSizer(self, title, sel): 
++        """!Helper layout function.
++        """
++        selSizer = wx.BoxSizer(orient = wx.VERTICAL)
++
++        selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
++        selTitleSizer.Add(item = title, proportion = 1,
++                          flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
++
++        selSizer.Add(item = selTitleSizer, proportion = 0,
++                     flag = wx.EXPAND)
++
++        selSizer.Add(item = sel, proportion = 1,
++                     flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
++                     border = 5)
++
++        return selSizer
++
++    def OnClose(self, event):
++        """!Close dialog
++        """
++        if not self.IsModal():
++            self.Destroy()
++        event.Skip()
++
++    def OnOk(self, event):
++        """!
++        """
++        band_1 = self.band_1_ch.GetSelection()
++        band_2 = self.band_2_ch.GetSelection()
++
++
++        if band_1 == band_2:
++            GError(_("Selected bands must be different."))
++            return
++        
++        #TODO axes selection
++        if band_1 > band_2:
++            tmp_band = band_2
++            band_2 = band_1
++            band_1 = band_2
++
++        self.scatt_id = idBandsToidScatt(band_1, band_2, len(self.bands))
++
++        event.Skip()
++
++    def GetScattId(self):
++        return self.scatt_id
 Index: gui/wxpython/scatt_plot/__init__.py
 ===================================================================
 --- gui/wxpython/scatt_plot/__init__.py	(revision 0)
@@ -2430,7 +2103,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/plots.py	(revision 0)
 +++ gui/wxpython/scatt_plot/plots.py	(working copy)
-@@ -0,0 +1,944 @@
+@@ -0,0 +1,943 @@
 +"""!
 + at package scatt_plot.dialogs
 +
@@ -2753,7 +2426,6 @@
 +        
 +        self.canvas.draw()
 +
-+
 +    def ZoomRectangle(self, event):
 +        # get the current x and y limits
 +        if not self.mode == "zoom": return
@@ -3380,7 +3052,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/controllers.py	(revision 0)
 +++ gui/wxpython/scatt_plot/controllers.py	(working copy)
-@@ -0,0 +1,816 @@
+@@ -0,0 +1,815 @@
 +"""!
 + at package scatt_plot.controllers
 +
@@ -3483,7 +3155,7 @@
 +        self.modeSet = Signal("ScattsManager.mondeSet")
 +
 +    def CleanUp(self):
-+        self.core.CleanUp()
++        self.thread.Run(callable=self.core.CleanUp)
 +        self.added_cats_rasts = []
 +
 +        self.cats_mgr.CleanUp()
@@ -3505,11 +3177,11 @@
 +        for init in initSettings: 
 +            UserSettings.ReadSettingsFile()
 +            UserSettings.Append(dict = UserSettings.userSettings, 
-+                                    group ='scatt',
-+                                    key = init[0],
-+                                    subkey =init[1],
-+                                    value = init[2],
-+                                    overwrite = False)
++                                group ='scatt',
++                                key = init[0],
++                                subkey =init[1],
++                                value = init[2],
++                                overwrite = False)
 +
 +    def OnThreadDone(self, event):
 +        
@@ -3566,7 +3238,6 @@
 +            return
 +
 +    def SetData(self, bands):
-+        "setting datas"
 +        self.CleanUp()
 +        self.data_set = False
 +        
@@ -3765,8 +3436,8 @@
 +        if not sel_cat_id:
 +            return
 +
-+        #for scatt in self.plots.itervalues():
-+        #    scatt.SetEmpty()
++        for scatt in self.plots.itervalues():
++            scatt.SetEmpty()
 +
 +        self.computingStarted.emit()
 +
@@ -4996,7 +4667,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/scatt_core.py	(revision 0)
 +++ gui/wxpython/scatt_plot/scatt_core.py	(working copy)
-@@ -0,0 +1,794 @@
+@@ -0,0 +1,795 @@
 +"""!
 + at package scatt_plot.scatt_plot
 +
@@ -5080,7 +4751,6 @@
 +        cats_ids = self.scatts_dt.GetCategories()
 +        self.ComputeCatsScatts(cats_ids)
 +
-+
 +    def SetEditCatData(self, cat_id, scatt_id, bbox, value):
 +
 +        if cat_id not in self.scatts_dt.GetCategories():
@@ -5285,42 +4955,42 @@
 +
 +    def _create_grass_region_env(self, bbox):
 +
-+        region = self.an_data.GetRegion()
-+        new_region = {}
++        r = self.an_data.GetRegion()
++        new_r = {}
 +
-+        if bbox["maxy"] <= region["s"]:
++        if bbox["maxy"] <= r["s"]:
 +            return 0
-+        elif bbox["maxy"] >= region["n"]:
-+            new_region["n"] = bbox["maxy"]
++        elif bbox["maxy"] >= r["n"]:
++            new_r["n"] = bbox["maxy"]
 +        else:
-+            new_region["n"] = ceil((bbox["maxy"] - region["s"]) / region["nsres"]) * region["nsres"] + region["s"]
++            new_r["n"] = ceil((bbox["maxy"] - r["s"]) / r["nsres"]) * r["nsres"] + r["s"]
 +
-+        if bbox["miny"] >= region["n"]:
++        if bbox["miny"] >= r["n"]:
 +            return 0
-+        elif bbox["miny"] <= region["s"]:
-+            new_region["s"] = bbox["miny"]
++        elif bbox["miny"] <= r["s"]:
++            new_r["s"] = bbox["miny"]
 +        else:
-+            new_region["s"] = floor((bbox["miny"] - region["s"]) / region["nsres"]) * region["nsres"] + region["s"]
++            new_r["s"] = floor((bbox["miny"] - r["s"]) / r["nsres"]) * r["nsres"] + r["s"]
 +
-+        if bbox["maxx"] <= region["w"]:
++        if bbox["maxx"] <= r["w"]:
 +            return 0
-+        elif bbox["maxx"] >= region["e"]:
-+            new_region["e"] = bbox["maxx"]
++        elif bbox["maxx"] >= r["e"]:
++            new_r["e"] = bbox["maxx"]
 +        else:
-+            new_region["e"] = ceil((bbox["maxx"] - region["w"]) / region["ewres"]) * region["ewres"] + region["w"]
++            new_r["e"] = ceil((bbox["maxx"] - r["w"]) / r["ewres"]) * r["ewres"] + r["w"]
 +
-+        if bbox["minx"] >= region["e"]:
++        if bbox["minx"] >= r["e"]:
 +            return 0
-+        elif bbox["minx"] <= region["w"]:
-+            new_region["w"] = bbox["minx"]
++        elif bbox["minx"] <= r["w"]:
++            new_r["w"] = bbox["minx"]
 +        else:
-+            new_region["w"] = floor((bbox["minx"] - region["w"]) / region["ewres"]) * region["ewres"] + region["w"]
++            new_r["w"] = floor((bbox["minx"] - r["w"]) / r["ewres"]) * r["ewres"] + r["w"]
 +
-+        #TODO check regions resolutin
-+        new_region["nsres"] = region["nsres"]
-+        new_region["ewres"] = region["ewres"]
++        #TODO check regions resolution
++        new_r["nsres"] = r["nsres"]
++        new_r["ewres"] = r["ewres"]
 +
-+        return {"GRASS_REGION" :  grass.region_env(**new_region)}
++        return {"GRASS_REGION" :  grass.region_env(**new_r)}
 +
 +class AnalyzedData:
 +
@@ -5596,11 +5266,12 @@
 +    def DeleteCategory(self, cat_id):
 +
 +        ScattPlotsCondsData.DeleteCategory(self, cat_id)
-+
++        
 +        grass.try_remove(self.cats_rasts_conds[cat_id])
 +        del self.cats_rasts_conds[cat_id]
 +
-+        grass.try_remove(self.cats_rasts[cat_id])
++        RunCommand("g.remove",
++                   rast=self.cats_rasts[cat_id])
 +        del self.cats_rasts[cat_id]
 +
 +        return True
@@ -5707,15 +5378,16 @@
 +    def CleanUp(self):
 +
 +        ScattPlotsCondsData.CleanUp(self)        
-+        for tmp in self.cats_rasts_conds:
++        for tmp in self.cats_rasts_conds.itervalues():
 +            grass.try_remove(tmp) 
-+        for tmp in self.cats_rasts:
-+            grass.try_remove(tmp) 
++        for tmp in self.cats_rasts.itervalues():
++            print RunCommand("g.remove",
++                            rast=tmp,
++                           getErrorMsg=True)
 +
 +        self.cats_rasts = {}
 +        self.cats_rasts_conds = {}
 +
-+
 +    def GetCatRast(self, cat_id):
 +        return self.cats_rasts[cat_id]
 +
@@ -5791,893 +5463,1232 @@
 +
 +    return scatt_id
 +
-Index: gui/wxpython/scatt_plot/core_c.py
+Index: lib/vector/Vlib/open.c
 ===================================================================
---- gui/wxpython/scatt_plot/core_c.py	(revision 0)
-+++ gui/wxpython/scatt_plot/core_c.py	(working copy)
-@@ -0,0 +1,203 @@
-+"""!
-+ at package scatt_plot.scatt_plot
+--- lib/vector/Vlib/open.c	(revision 57644)
++++ lib/vector/Vlib/open.c	(working copy)
+@@ -240,7 +240,9 @@
+         }
+         else {
+             char file_path[GPATH_MAX];
+-            
++            /* reduce to current mapset if search path was set */
++            if(strcmp(Map->mapset, "") == 0)
++                Map->mapset = G_store(G_mapset());
+             /* temporary map: reduce to current mapset if search path
+              * was set */
+             if (strcmp(Map->mapset, "") == 0)
+Index: lib/imagery/scatt.c
+===================================================================
+--- lib/imagery/scatt.c	(revision 0)
++++ lib/imagery/scatt.c	(working copy)
+@@ -0,0 +1,799 @@
++/*!
++   \file lib/imagery/scatt.c
 +
-+ at brief Functions which work with scatter plot c code.
++   \brief Imagery library - functions for wx Scatter Plot Tool.
 +
-+Classes:
++   Low level functions used by wx Scatter Plot Tool.
 +
-+(C) 2013 by the GRASS Development Team
++   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.
++   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)
-+"""
++   \author Stepan Turek <stepan.turek at seznam.cz> (Mentor: Martin Landa)
++ */
 +
-+#TODO just for testing
-+import time
++#include <grass/raster.h>
++#include <grass/imagery.h>
++#include <grass/gis.h>
++#include <grass/glocale.h>
 +
-+import sys
-+from multiprocessing import Process, Queue
++#include <stdio.h>
++#include <stdlib.h>
++#include <math.h>
++#include <string.h>
 +
-+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 ctypes libs failed"))
 +
-+from core.gcmd import GException
++struct rast_row
++{
++    CELL * row;
++    char * null_row;
++    struct Range rast_range; /*Range of whole raster.*/
++};
 +
-+def ApplyColormap(vals, vals_mask, colmap, out_vals):
++/*!
++   \brief Create pgm header.
++
++   Scatter plot internally generates pgm files. These pgms have header in format created by this function.
 +    
-+    c_uint8_p = POINTER(c_uint8)
-+    c_double_p = POINTER(c_double)
++   \param region region to be pgm header generated for 
++   \param [out] header header of pgm file
++ */
++static int get_cat_rast_header(struct Cell_head * region, char * header){
++    return sprintf(header, "P5\n%d\n%d\n1\n", region->cols, region->rows);
++}
 +
++/*!
++   \brief Create category raster conditions file.
++    
++   \param cat_rast_region region to be file generated for
++   \param cat_rast path of generated category raster file
++ */
++int I_create_cat_rast(struct Cell_head * cat_rast_region,  const char * cat_rast)
++{
++    FILE * f_cat_rast;
++    char cat_rast_header[1024];//TODO magic number 
++    int i_row, i_col;
++    int head_nchars;
 +
-+    vals_p = vals.ctypes.data_as(c_uint8_p)
-+    vals_mask_p = vals_mask.ctypes.data_as(c_uint8_p)
-+    colmap_p = colmap.ctypes.data_as(c_uint8_p)
-+    out_vals_p = out_vals.ctypes.data_as(c_uint8_p)
++    unsigned char * row_data;
 +
-+    vals_size = vals.reshape((-1)).shape[0]
-+    I_apply_colormap(vals_p, vals_mask_p, vals_size, colmap_p, out_vals_p)
++    f_cat_rast = fopen(cat_rast, "wb");
++    if(!f_cat_rast) {
++        G_warning("Unable to create category raster condition file <%s>.", cat_rast);
++        return -1;
++    }
 +
-+def MergeArrays(merged_arr, overlay_arr, alpha):
-+    if merged_arr.shape != overlay_arr.shape:
-+        GException("MergeArrays: merged_arr.shape != overlay_arr.shape")
++    head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
 +
-+    c_uint8_p = POINTER(c_uint8)
-+    merged_p = merged_arr.ctypes.data_as(c_uint8_p)
-+    overlay_p = overlay_arr.ctypes.data_as(c_uint8_p)
++    fwrite(cat_rast_header, sizeof(char), head_nchars/sizeof(char), f_cat_rast);
++    if (ferror(f_cat_rast)){
++        fclose(f_cat_rast);
++        G_warning(_("Unable to write header into category raster condition file <%s>."), cat_rast);
++        return -1;
++    }
 +
-+    I_merge_arrays(merged_p, overlay_p, merged_arr.shape[0], merged_arr.shape[1], alpha)
++    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;
 +
-+def MergeArrays(merged_arr, overlay_arr, alpha):
-+    if merged_arr.shape != overlay_arr.shape:
-+        GException("MergeArrays: merged_arr.shape != overlay_arr.shape")
++    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);
++        if (ferror(f_cat_rast))
++        {
++            fclose(f_cat_rast);
++            G_warning(_("Unable to write into category raster condition file <%s>."), cat_rast);
++            return -1;
++        }
++    }
 +
-+    c_uint8_p = POINTER(c_uint8)
-+    merged_p = merged_arr.ctypes.data_as(c_uint8_p)
-+    overlay_p = overlay_arr.ctypes.data_as(c_uint8_p)
++    fclose(f_cat_rast);
++    return 0;
++}
 +
-+    I_merge_arrays(merged_p, overlay_p, merged_arr.shape[0], merged_arr.shape[1], alpha)
++static int print_reg(struct Cell_head * intersec, const char * pref, int dbg_level)
++{
++    G_debug(dbg_level, "%s:\n n:%f\ns:%f\ne:%f\nw:%f\nns_res:%f\new_res:%f", pref, intersec->north, intersec->south, 
++               intersec->east, intersec->west, intersec->ns_res, intersec->ew_res);
++}
 +
-+def ComputeScatts(region, scatt_conds, bands, n_bands, scatts, cats_rasts_conds, cats_rasts):
++/*!
++   \brief Find intersection region of two regions.
 +
-+    q = Queue()
-+    p = Process(target=_computeScattsProcess, args=(region, scatt_conds, bands, 
-+                                                    n_bands, scatts, cats_rasts_conds, cats_rasts, q))
-+    p.start()
-+    ret = q.get()
-+    p.join()
-+    
-+    return ret[0], ret[1]
++   \param A pointer to intersected region
++   \param B pointer to intersected region
++   \param [out] intersec pointer to intersection region of regions A B (relevant params of the region are: south, north, east, west)
 +
-+def UpdateCatRast(patch_rast, region, cat_rast):
-+    q = Queue()
-+    p = Process(target=_updateCatRastProcess, args=(patch_rast, region, cat_rast, q))
-+    p.start()
-+    ret = q.get()
-+    p.join()
++   \return  0 if interection exists
++   \return -1 if regions does not intersect
++ */
++static int regions_intersecion(struct Cell_head * A, struct Cell_head * B, struct Cell_head * intersec)
++{
 +
-+    return ret
++    if(B->north < A->south) return -1;
++    else if(B->north > A->north) intersec->north = A->north;
++    else intersec->north = B->north;
 +
-+def CreateCatRast(region, cat_rast):
-+    cell_head = _regionToCellHead(region)
-+    I_create_cat_rast(pointer(cell_head), cat_rast)   
++    if(B->south > A->north) return -1;
++    else if(B->south < A->south) intersec->south = A->south;
++    else intersec->south = B->south;
 +
-+def _computeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts_conds, cats_rasts, output_queue):
++    if(B->east < A->west) return -1;
++    else if(B->east > A->east) intersec->east = A->east;
++    else intersec->east = B->east;
 +
-+    #TODO names for types not 0 and 1?
-+    sccats_c, cats_rasts_c, refs = _getComputationStruct(scatts, cats_rasts, SC_SCATT_DATA, n_bands)
-+    scatt_conds_c, cats_rasts_conds_c, refs2 = _getComputationStruct(scatt_conds, cats_rasts_conds, SC_SCATT_CONDITIONS, n_bands)
++    if(B->west > A->east) return -1;
++    else if(B->west < A->west) intersec->west = A->west;
++    else intersec->west = B->west;
 +
-+    char_bands = _stringListToCharArr(bands)
-+   
-+    cell_head = _regionToCellHead(region)
++    if(intersec->north == intersec->south) return -1;
 +
-+    ret = I_compute_scatts(pointer(cell_head),
-+                           pointer(scatt_conds_c),
-+                           pointer(cats_rasts_conds_c),
-+                           pointer(char_bands),
-+                           n_bands,
-+                           pointer(sccats_c),
-+                           pointer(cats_rasts_c))
++    if(intersec->east == intersec->west) return -1;
 +
-+    I_sc_free_cats(pointer(sccats_c))
-+    I_sc_free_cats(pointer(scatt_conds_c))
++    return 0;
 +
-+    output_queue.put((ret, scatts))
++}
 +
-+def _getBandcRange( band_info):
-+    band_c_range = struct_Range()
++/*!
++   \brief Get rows and cols numbers, which defines intersection of the regions.
++  
++   \param A pointer to intersected region
++   \param B pointer to intersected region (A and B must have same resolution)
++   \param [out] A_bounds rows and cols numbers of A stored in south, north, east, west, which defines intersection of A and B
++   \param [out] B_bounds rows and cols numbers of B stored in south, north, east, west, which defines intersection of A and B
 +
-+    band_c_range.max = band_info['max']
-+    band_c_range.min = band_info['min']
++   \return  0 if interection exists
++   \return -1 if regions do not intersect
++   \return -2 resolution of regions is not same 
++*/
++static int get_rows_and_cols_bounds(struct Cell_head * A,  struct Cell_head * B, struct Cell_head * A_bounds,  struct Cell_head * B_bounds)
++{
++    float ns_res, ew_res;
 +
-+    return band_c_range
++    struct Cell_head intersec;
 +
-+def _regionToCellHead(region):
-+    cell_head = struct_Cell_head()
-+    G_get_window(pointer(cell_head))
++    /* TODO is it right check? */
++    if(abs(A->ns_res - B->ns_res) > GRASS_EPSILON) {
++        G_debug(0, "'get_rows_and_cols_bounds' ns_res does not fit, A->ns_res: %f B->ns_res: %f", A->ns_res, B->ns_res);
++        return -2;
++    }
 +
-+    convert_dict = {'n' : 'north', 'e' : 'east', 
-+                    'w' : 'west',  's' : 'south', 
-+                    'nsres' : 'ns_res',
-+                    'ewres' : 'ew_res'}
++    if(abs(A->ew_res - B->ew_res) > GRASS_EPSILON) {
++        G_debug(0, "'get_rows_and_cols_bounds' ew_res does not fit, A->ew_res: %f B->ew_res: %f", A->ew_res, B->ew_res);
++        return -2;
++    }
 +
-+    for k, v in region.iteritems():
-+        if k in ["rows", "cols", "cells"]:
-+            v = int(v)
-+        else:
-+            v = float(v)
++    ns_res = A->ns_res;
++    ew_res = A->ew_res;
 +
-+        if convert_dict.has_key(k):
-+            k = convert_dict[k]
-+           
-+        setattr(cell_head, k, v)
++    if(regions_intersecion(A, B, &intersec) == -1)
++        return -1;
 +
-+    return cell_head
++    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);
 +
-+def _stringListToCharArr(str_list):
++    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);
 +
-+    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
++    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);
 +
-+    return char_arr
++    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);
 +
-+def _getComputationStruct(cats, cats_rasts, cats_type, n_bands):
++    return 0;
++}
 +
-+    sccats = struct_scCats()
-+    I_sc_init_cats(pointer(sccats), c_int(n_bands), c_int(cats_type));
++/*!
++   \brief Insert raster map patch into pgm file.
++  
++   \param patch_rast name of raster map
++   \param cat_rast_region region of category raster file
++   \param cat_rast path to category raster file
 +
-+    refs = []        
-+    cats_rasts_core = []
-+    
-+    for cat_id, scatt_ids in cats.iteritems():
-+        cat_c_id = I_sc_add_cat(pointer(sccats))
-+        cats_rasts_core.append(cats_rasts[cat_id])
++   \return  0 on success
++   \return -1 on failure
++*/
++int I_insert_patch_to_cat_rast(const char * patch_rast, struct Cell_head * cat_rast_region,  const char * cat_rast)
++{
 +
-+        for scatt_id, dt in scatt_ids.iteritems():
-+            # if key is missing condition is always True (full scatter plor is computed)
-+                vals = dt['np_vals']
++    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, ret;
++    int fd_patch_rast, init_shift, step_shift;
++    unsigned char * patch_data;
 +
-+                scatt_vals = scdScattData()
++    char * null_chunk_row;
 +
-+                c_void_p = ctypes.POINTER(ctypes.c_void_p)
++    const char *mapset;
 +
-+                if cats_type == SC_SCATT_DATA:
-+                    vals[:] = 0
-+                elif cats_type == SC_SCATT_CONDITIONS:
-+                    pass
-+                else:
-+                    return None
-+                data_p = vals.ctypes.data_as(c_void_p)
-+                I_scd_init_scatt_data(pointer(scatt_vals), cats_type, len(vals), data_p)
++    struct Cell_head patch_lines, cat_rast_lines;
 +
-+                refs.append(scatt_vals)
++    unsigned char * row_data;
 +
-+                I_sc_insert_scatt_data(pointer(sccats),  
-+                                       pointer(scatt_vals),
-+                                       cat_c_id, scatt_id)
++    f_cat_rast = fopen(cat_rast, "rb+");
++    if(!f_cat_rast) {
++        G_warning(_("Unable to open category raster condtions file <%s>."), cat_rast);
++        return -1;
++    }
 +
-+    cats_rasts_c = _stringListToCharArr(cats_rasts_core)
++    head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
++    if ((mapset = G_find_raster(patch_rast,"")) == NULL) {
++        fclose(f_cat_rast);
++        G_warning(_("Unable to find patch raster <%s>."), patch_rast);
++        return -1;
++    }
 +
-+    return sccats, cats_rasts_c, refs
++    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 -1;
++    }
 +
-+def _updateCatRastProcess(patch_rast, region, cat_rast, output_queue):
-+    cell_head = _regionToCellHead(region)
-+    
-+    
-+    ret = I_insert_patch_to_cat_rast(patch_rast, 
-+                                     pointer(cell_head), 
-+                                     cat_rast)
++    ret = get_rows_and_cols_bounds(cat_rast_region, &patch_region, &cat_rast_bounds, &patch_bounds);
++    if(ret == -2) { 
++        G_warning(_("Resolutions of patch <%s> and patched file <%s> are not same."), patch_rast, cat_rast);
 +
-+    output_queue.put(ret)
++        Rast_close(fd_patch_rast);
++        fclose(f_cat_rast);
 +
++        return -1;
++    }
++    else if (ret == -1){
 +
-Index: gui/wxpython/scatt_plot/frame.py
-===================================================================
---- gui/wxpython/scatt_plot/frame.py	(revision 0)
-+++ gui/wxpython/scatt_plot/frame.py	(working copy)
-@@ -0,0 +1,624 @@
-+"""!
-+ at package scatt_plot.dialogs
++        Rast_close(fd_patch_rast);
++        fclose(f_cat_rast);
 +
-+ at brief GUI.
++        return 0;
++    }
 +
-+Classes:
++    ncols = cat_rast_bounds.east - cat_rast_bounds.west;
++    nrows = cat_rast_bounds.south - cat_rast_bounds.north;
 +
-+(C) 2013 by the GRASS Development Team
++    patch_data = (unsigned char *) G_malloc(ncols * sizeof(unsigned char));
 +
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
++    init_shift = head_nchars + cat_rast_region->cols * cat_rast_bounds.north + cat_rast_bounds.west;
 +
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+import os
-+import sys
++    if(fseek(f_cat_rast, init_shift, SEEK_SET) != 0) {
++        G_warning(_("Corrupted  category raster conditions file <%s> (fseek failed)"), cat_rast);
 +
-+import wx
-+import wx.lib.scrolledpanel as scrolled
-+import wx.lib.mixins.listctrl as listmix
++        Rast_close(fd_patch_rast);
++        G_free(null_chunk_row);
++        fclose(f_cat_rast);
 +
-+from core import globalvar
-+from core.gcmd import GException, GError, RunCommand
++        return -1;
++    }
 +
-+from gui_core.gselect import Select
-+from gui_core.dialogs import SetOpacityDialog
++    step_shift = cat_rast_region->cols - ncols;
 +
-+from scatt_plot.controllers import ScattsManager
-+from scatt_plot.toolbars import MainToolbar, EditingToolbar
-+from scatt_plot.scatt_core import idScattToidBands
-+from scatt_plot.plots import ScatterPlotWidget
-+from vnet.dialogs import VnetStatusbar
++    null_chunk_row =  Rast_allocate_null_buf();
++    
++    for(i_row = 0; i_row < nrows; i_row++) {
++        Rast_get_null_value_row (fd_patch_rast, null_chunk_row, i_row + patch_bounds.north);
 +
-+try:
-+    from agw import aui
-+except ImportError:
-+    import wx.lib.agw.aui as aui
++        for(i_col = 0; i_col < ncols; i_col++) {
++            patch_col = patch_bounds.west + i_col;
 +
-+class IClassScatterPlotsPanel(wx.Panel):
-+    def __init__(self, parent, giface, iclass_mapwin = None,
-+                 id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
++            if(null_chunk_row[patch_col] != 1) 
++                patch_data[i_col] = 1 & 255;
++            else {
++                patch_data[i_col] = 0 & 255;
++            }
++        }
 +
-+        #wx.SplitterWindow.__init__(self, parent = parent, id = id,
-+        #                           style = wx.SP_LIVE_UPDATE)
-+        wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
++        fwrite(patch_data, sizeof(unsigned char), (ncols)/sizeof(unsigned char), f_cat_rast);
++        if (ferror(f_cat_rast))
++        {
++            G_warning(_("Unable to write into category raster conditions file <%s>"), cat_rast);
++            
++            Rast_close(fd_patch_rast);
++            G_free(null_chunk_row);
++            fclose(f_cat_rast);
 +
-+        #self.head_panel = wx.Panel(parent = self, id = wx.ID_ANY)
-+        self.scatt_mgr = ScattsManager(guiparent = self, giface = giface, iclass_mapwin = iclass_mapwin)
++            return -1;
++        }
++        if(fseek(f_cat_rast, step_shift, SEEK_CUR) != 0) {
++            G_warning(_("Corrupted  category raster conditions file <%s> (fseek failed)"), cat_rast);
++            
++            Rast_close(fd_patch_rast);
++            G_free(null_chunk_row);
++            fclose(f_cat_rast);
++            
++            return -1;
++        }
++    }
 +
-+        # toobars
-+        self.toolbars = {}
-+        self.toolbars['mainToolbar'] = MainToolbar(parent = self, scatt_mgr = self.scatt_mgr)
-+        self.toolbars['editingToolbar'] = EditingToolbar(parent = self, scatt_mgr = self.scatt_mgr)
-+        
-+        self._createCategoryPanel(self)
++    Rast_close(fd_patch_rast);
++    G_free(null_chunk_row);
++    fclose(f_cat_rast);
++    return 0;
++}
 +
-+        self.plot_panel = IClassPlotPanel(self, self.scatt_mgr)
++/*!
++   \brief Updates scatter plots data in category by pixels which meets category conditions.
++  
++   \param bands_rows data represents data describig one row from raster band
++   \param belongs_pix array which defines which pixels belongs to category (1 value) and which not (0 value)
++   \param [out] scatts pointer to scScatts struct of type SC_SCATT_DATA, which are modified according to values in belongs_pix
++*/
++static inline void update_cat_scatt_plts(struct rast_row * bands_rows, unsigned short * belongs_pix, struct scScatts * scatts)
++{
++    int band_axis_1, band_axis_2, i_scatt, array_idx, cat_idx, i_chunk_rows_pix, max_arr_idx;
 +
-+        # statusbar
-+        self.stPriors = {'high' : 5, 'info' : 1}
-+        self.stBar = VnetStatusbar(parent = self, style = 0)
-+        self.stBar.SetFieldsCount(number = 1)
++    CELL * b_1_row;
++    CELL * b_2_row;
++    char * b_1_null_row,* b_2_null_row;
++    struct rast_row b_1_rast_row, b_2_rast_row;
 +
-+        mainsizer = wx.BoxSizer(wx.VERTICAL)
-+        mainsizer.Add(item = self.toolbars['mainToolbar'], proportion = 0, flag = wx.EXPAND)
-+        mainsizer.Add(item = self.toolbars['editingToolbar'], proportion = 0, flag = wx.EXPAND)
-+        mainsizer.Add(item = self.catsPanel, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT , border = 5)
-+        mainsizer.Add(item = self.plot_panel, proportion = 1, flag = wx.EXPAND)
-+        mainsizer.Add(item = self.stBar, proportion = 0)
++    struct Range b_1_range, b_2_range;
++    int b_1_range_size;
 +
-+        self.catsPanel.Hide()
-+        self.toolbars['editingToolbar'].Hide()
++    int row_size = Rast_window_cols();
 +
-+        self.SetSizer(mainsizer)
++    int * scatts_bands = scatts->scatts_bands;
++
++    for(i_scatt = 0; i_scatt < scatts->n_a_scatts; i_scatt++)
++    {   
++        b_1_rast_row = bands_rows[scatts_bands[i_scatt * 2]];
++        b_2_rast_row = bands_rows[scatts_bands[i_scatt * 2 + 1]];
++
++        b_1_row = b_1_rast_row.row;
++        b_2_row = b_2_rast_row.row;
++
++        b_1_null_row =  b_1_rast_row.null_row;
++        b_2_null_row =  b_2_rast_row.null_row;
++
++        b_1_range = b_1_rast_row.rast_range;
++        b_2_range = b_2_rast_row.rast_range;
 +        
-+        self.scatt_mgr.cursorPlotMove.connect(self.CursorPlotMove)
-+        self.scatt_mgr.renderingStarted.connect(lambda : self.stBar.AddStatusItem(text=_("Rendering..."), 
-+                                                                                 key='comp', 
-+                                                                                 priority=self.stPriors['high']))
-+        self.scatt_mgr.renderingFinished.connect(lambda : self.stBar.RemoveStatusItem(key='comp'))
++        b_1_range_size = b_1_range.max - b_1_range.min + 1;
++        max_arr_idx = (b_1_range.max -  b_1_range.min + 1) * (b_2_range.max -  b_2_range.min + 1);
 +
-+        self.scatt_mgr.computingStarted.connect(lambda : self.stBar.AddStatusItem(text=_("Computing data..."), 
-+                                                                                 key='comp', 
-+                                                                                 priority=self.stPriors['high']))
++        for(i_chunk_rows_pix = 0; i_chunk_rows_pix < row_size; i_chunk_rows_pix++)
++        {
++            /* pixel does not belongs to scatter plot or has null value in one of the bands */
++            if(!belongs_pix[i_chunk_rows_pix] || 
++                b_1_null_row[i_chunk_rows_pix] == 1 || 
++                b_2_null_row[i_chunk_rows_pix] == 1)                
++                continue;
 +
-+        #self.SetSashGravity(0.5)
-+        #self.SplitHorizontally(self.head_panel, self.plot_panel, -50)
-+        self.Layout()
++            /* index in scatter plot array */
++            array_idx = b_1_row[i_chunk_rows_pix] - b_1_range.min + (b_2_row[i_chunk_rows_pix] - b_2_range.min) * b_1_range_size;
 +
-+    def CursorPlotMove(self, x, y):
++            if(array_idx < 0 || array_idx >= max_arr_idx) {
++                        G_warning ("Data inconsistent. Value computed for scatter plot is out of initialized range.");
++                continue;
++            }
 +
-+        x = int(round(x))
-+        y = int(round(y))
-+        self.stBar.AddStatusItem(text="%d; %d" % (x, y), 
-+                                 key='coords', 
-+                                 priority=self.stPriors['info'])
++            /* increment scatter plot value */
++            ++scatts->scatts_arr[i_scatt]->scatt_vals_arr[array_idx];
++        }
++    }
++}
 +
++/*!
++   \brief Computes scatter plots data from chunk_rows.
 +
-+    def NewScatterPlot(self, scatt_id, transpose):
-+        return self.plot_panel.NewScatterPlot(scatt_id, transpose)
++   \param scatts pointer to scScatts struct of type SC_SCATT_DATA, where are computed scatter plots stored
++   \param scatt_conds pointer to scScatts struct of type SC_SCATT_CONDITIONS, where are selected areas (condtitions)stored
 +
-+    def ShowPlotEditingToolbar(self, show):
-+        self.toolbars["editingToolbar"].Show(show)
-+        self.Layout()
++   \param chunk_rows data arrays of chunk_rows from analyzed raster bands (all data in chunk_rows, null_chunk_rows and belongs_pix arrays represents same region)
++   \param null_chunk_rows null data arrays of chunk_rows from analyzed raster bands
++   \param row_size size of data in chunk_rows, null_chunk_rows and belongs_pix arrays
++   \param f_cats_rasts_conds file which stores selected areas (conditions) from mapwindow see I_create_cat_rast() and I_pa
++   \param fd_cats_rasts array of openedraster maps which represents all selected pixels for category
++   \param region analysis region
 +
-+    def ShowCategoryPanel(self, show):
-+        self.catsPanel.Show(show)
-+        
-+        #if show:
-+        #    self.SetSashSize(5) 
-+        #else:
-+        #    self.SetSashSize(0)
-+        self.plot_panel.SetVirtualSize(self.plot_panel.GetBestVirtualSize())
-+        self.Layout()
++   \return  0 on success
++   \return -1 on failure
++*/
++static inline int compute_scatts_from_chunk_row(struct Cell_head *region, struct scCats * scatt_conds, 
++                                                FILE ** f_cats_rasts_conds, struct rast_row * bands_rows, 
++                                                struct scCats * scatts, int * fd_cats_rasts)
++{
 +
-+    def _createCategoryPanel(self, parent):
-+        self.catsPanel = wx.Panel(parent = parent)
-+        self.cats_list = CategoryListCtrl(parent = self.catsPanel, 
-+                                          cats_mgr = self.scatt_mgr.GetCategoriesManager())
++    int i_rows_pix, i_cat, i_scatt, n_a_scatts, n_pixs;
++    int cat_id, scatt_plts_cat_idx, array_idx, max_arr_idx;
++    char * b_1_null_row,* b_2_null_row;
++    struct rast_row b_1_rast_row, b_2_rast_row;
++    CELL * cat_rast_row;
 +
-+        self.catsPanel.SetMaxSize((-1, 150))
++    struct scScatts * scatts_conds;
++    struct scScatts * scatts_scatt_plts;
++    struct scdScattData * conds;
 +
-+        box_capt = wx.StaticBox(parent = self.catsPanel, id = wx.ID_ANY,
-+                             label = ' %s ' % _("Classes manager for scatter plots"))
-+        catsSizer = wx.StaticBoxSizer(box_capt, wx.VERTICAL)
++    struct Range b_1_range, b_2_range;
++    int b_1_range_size;
 +
-+        catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND | wx.ALL)
-+        self.catsPanel.SetSizer(catsSizer)
++    int * scatts_bands;
++    struct scdScattData ** scatts_arr;
 +
++    CELL * b_1_row;
++    CELL * b_2_row;
++    unsigned char * i_scatt_conds;
 +
-+class IClassPlotPanel(scrolled.ScrolledPanel):
-+    def __init__(self, parent, scatt_mgr, id = wx.ID_ANY):
-+    
-+        scrolled.ScrolledPanel.__init__(self, parent)
-+        self.SetupScrolling(scroll_x = False, scroll_y = True, scrollToTop = False)
++    int row_size = Rast_window_cols();
 +
-+        self.scatt_mgr = scatt_mgr
++    unsigned short * belongs_pix = (unsigned short *) G_malloc(row_size * sizeof(unsigned short)); 
++    unsigned char * rast_pixs = (unsigned char *) G_malloc(row_size * sizeof(unsigned char));
++    cat_rast_row =  Rast_allocate_c_buf();
 +
-+        self.mainPanel = wx.Panel(parent = self, id = wx.ID_ANY)
++     
++    for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
++    {
++        scatts_conds = scatt_conds->cats_arr[i_cat];
 +
-+        #self._createCategoryPanel()
-+        # Fancy gui
-+        self._mgr = aui.AuiManager(self.mainPanel)
-+        #self._mgr.SetManagedWindow(self)
++        cat_id = scatt_conds->cats_ids[i_cat];
 +
-+        self._mgr.Update()
++        scatt_plts_cat_idx = scatts->cats_idxs[cat_id];
++        if(scatt_plts_cat_idx < 0)
++            continue;
++        scatts_scatt_plts = scatts->cats_arr[scatt_plts_cat_idx];
 +
-+        self._doLayout()
-+        self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
-+        self.Bind(wx.EVT_SCROLL_CHANGED, self.OnScrollChanged)
++        G_zero(belongs_pix, row_size * sizeof(unsigned short));
 +
-+        self.Bind(aui.EVT_AUI_PANE_CLOSE, self.OnPlotPaneClosed)
++        /* if category has no conditions defined, scatter plots without any constraint are computed (default scatter plots) */
++        if(!scatts_conds->n_a_scatts && !f_cats_rasts_conds[i_cat]) {
++            for(i_scatt = 0; i_scatt < scatts_scatt_plts->n_a_scatts; i_scatt++)
++            {       
++                /* all pixels belongs */
++                for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)                
++                    belongs_pix[i_rows_pix] = 1;
++            }
++        }
++        /* compute belonging pixels for defined conditions */
++        else
++        {
++            scatts_bands = scatts_conds->scatts_bands;
 +
-+        dlgSize = (-1, 400)
-+        #self.SetBestSize(dlgSize)
-+        #self.SetInitialSize(dlgSize)
-+        self.SetAutoLayout(1)
-+        #fix goutput's pane size (required for Mac OSX)
-+        #if self.gwindow:         
-+        #    self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
-+        self.ignore_scroll = 0
-+        self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
++            /* check conditions from category raster condtitions file */
++            if(f_cats_rasts_conds[i_cat]) {
++                n_pixs = fread(rast_pixs, sizeof(unsigned char), (row_size)/sizeof(unsigned char), f_cats_rasts_conds[i_cat]);
 +
-+    def ScatterPlotClosed(self, scatt_id):
-+        name = self._getScatterPlotName(scatt_id) 
-+        pane = self._mgr.GetPane(name)
++                if (ferror(f_cats_rasts_conds[i_cat]))
++                {
++                    G_free(rast_pixs);
++                    G_free(belongs_pix);
++                    G_warning(_("Unable to read from category raster condtition file."));
++                    return -1;
++                }
++                if (n_pixs != n_pixs) {
++                    G_free(rast_pixs);
++                    G_free(belongs_pix);
++                    G_warning(_("Invalid size of category raster conditions file."));
++                    return -1;
 +
-+        if pane.IsOk(): 
-+          self._mgr.ClosePane(pane) 
-+          self._mgr.Update() 
++                }
 +
-+    def OnMouseWheel(self, event):
-+        #TODO very ugly find some better solution        
-+        self.ignore_scroll = 3
-+        event.Skip()
++                for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)
++                {
++                    if(rast_pixs[i_rows_pix] != 0 & 255)
++                        belongs_pix[i_rows_pix] = 1;
++                }
++            }
 +
-+    def ScrollChildIntoView(self, child):
-+        #For aui manager it does not work and returns position always to the top -> deactivated.
-+        pass
++            /* check condtions defined in scatter plots*/
++            for(i_scatt = 0; i_scatt < scatts_conds->n_a_scatts; i_scatt++)
++            {   
++                b_1_rast_row = bands_rows[scatts_bands[i_scatt * 2]];
++                b_2_rast_row = bands_rows[scatts_bands[i_scatt * 2 + 1]];
 +
-+    def OnPlotPaneClosed(self, event):
-+        if isinstance(event.pane.window, ScatterPlotWidget):
-+            event.pane.window.CleanUp()
++                b_1_row = b_1_rast_row.row;
++                b_2_row = b_2_rast_row.row;
 +
-+    def OnScrollChanged(self, event):
-+        wx.CallAfter(self.Layout)
++                b_1_null_row =  b_1_rast_row.null_row;
++                b_2_null_row =  b_2_rast_row.null_row;
 +
-+    def OnScroll(self, event):
-+        if self.ignore_scroll > 0:
-+            self.ignore_scroll -= 1
-+        else:
-+            event.Skip()
++                b_1_range = b_1_rast_row.rast_range;
++                b_2_range = b_2_rast_row.rast_range;
 +
-+        #wx.CallAfter(self._mgr.Update)
-+        #wx.CallAfter(self.Layout)
++                b_1_range_size = b_1_range.max - b_1_range.min + 1;
++                max_arr_idx = (b_1_range.max -  b_1_range.min + 1) * (b_2_range.max -  b_2_range.min + 1);
 +
-+    def _doLayout(self):
++                i_scatt_conds = scatts_conds->scatts_arr[i_scatt]->b_conds_arr;
 +
-+        mainsizer = wx.BoxSizer(wx.VERTICAL)
-+        mainsizer.Add(item = self.mainPanel, proportion = 1, flag = wx.EXPAND)
-+        self.SetSizer(mainsizer)
++                for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)
++                {
++                    /* pixels already belongs to category from category raster conditions file or contains null value in one of the bands */
++                    if(belongs_pix[i_rows_pix] || 
++                       b_1_null_row[i_rows_pix] == 1 || 
++                       b_2_null_row[i_rows_pix] == 1)
++                        continue;
 +
-+        self.Layout()
-+        self.SetupScrolling()
++                    array_idx = b_1_row[i_rows_pix] - b_1_range.min + (b_2_row[i_rows_pix] - b_2_range.min) * b_1_range_size;
++                    if(array_idx < 0 || array_idx >= max_arr_idx) {
++                        G_warning ("Data inconsistent. Value computed for scatter plot is out of initialized range.");
++                        continue;
++                    }
++                    /* pixels meets condtion defined in scatter plot */
++                    if(i_scatt_conds[array_idx])
++                        belongs_pix[i_rows_pix] = 1;
++                }                
++            }
++        }
 +
-+    def OnCloseDialog(self, event):
-+        """!Close dialog"""
-+        self.scatt_mgr.CleanUp()
-+        self.Destroy()
++        /* update category raster with belonging pixels */
++        if(fd_cats_rasts[i_cat] >= 0) {
++            Rast_set_null_value(cat_rast_row, Rast_window_cols(), CELL_TYPE); 
 +
-+    def OnSettings(self, event):
-+        pass
++            for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)
++                if(belongs_pix[i_rows_pix])
++                    cat_rast_row[i_rows_pix] = belongs_pix[i_rows_pix];
 +
-+    def _getScatterPlotName(self, scatt_id):
-+        return "scatter plot %d" % scatt_id
++            Rast_put_c_row (fd_cats_rasts[i_cat], cat_rast_row); 
++        }
 +
-+    def NewScatterPlot(self, scatt_id, transpose):
-+        #TODO needs to be resolved (should be in this class)
++        /* update scatter plots with belonging pixels */
++        update_cat_scatt_plts(bands_rows, belongs_pix, scatts_scatt_plts);
++    }
 +
-+        scatt = ScatterPlotWidget(parent = self.mainPanel, 
-+                                  scatt_mgr = self.scatt_mgr, 
-+                                  scatt_id = scatt_id, 
-+                                  transpose = transpose)
-+        scatt.plotClosed.connect(self.ScatterPlotClosed)
++    G_free(cat_rast_row);
++    G_free(rast_pixs);
++    G_free(belongs_pix);
 +
-+        bands = self.scatt_mgr.GetBands()
++    return 0;
++}
 +
-+        #TODO too low level
-+        b1_id, b2_id = idScattToidBands(scatt_id, len(bands))
++/*!
++   \brief Get list if bands needed to be opened for analysis from scCats struct.
++*/
++static void get_needed_bands(struct scCats * cats, int * b_needed_bands)
++{
++    // results in b_needed_bands - array of bools - if item has value 1, band (defined by item index) is needed to be opened
++    int i_cat, i_scatt, cat_id;
 +
-+        x_b =  bands[b1_id].split('@')[0]
-+        y_b = bands[b2_id].split('@')[0]
++    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);
 +
-+        if transpose:
-+            tmp = x_b
-+            x_b = y_b
-+            y_b = tmp
++            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;
++}
 +
-+        caption = "%s x: %s y: %s" % (_("scatter plot"), x_b, y_b)
++/*!
++   \brief Helper function for clean up.
++*/
++static void free_compute_scatts_data(int * fd_bands, struct rast_row * bands_rows, int n_a_bands, int * bands_ids, 
++                                     int * fd_cats_rasts, FILE ** f_cats_rasts_conds, int n_a_cats)
++{
++    int i, band_id;
 +
-+        self._mgr.AddPane(scatt,
-+                           aui.AuiPaneInfo().Dockable(True).Floatable(True).
-+                           Name(self._getScatterPlotName(scatt_id)).MinSize((-1, 300)).
-+                           Caption(caption).
-+                           Center().Position(1).MaximizeButton(True).
-+                           MinimizeButton(True).CaptionVisible(True).
-+                           CloseButton(True).Layer(0))
-+        
++    for(i = 0; i < n_a_bands; i++)
++    {   
++        band_id = bands_ids[i];
++        if(band_id >= 0) {
++            Rast_close(fd_bands[i]);
++            G_free(bands_rows[band_id].row);
++            G_free(bands_rows[band_id].null_row);
++        }
++    }
++     
++    if(f_cats_rasts_conds)
++        for(i = 0; i < n_a_cats; i++)
++            if(f_cats_rasts_conds[i])
++                fclose(f_cats_rasts_conds[i]);
 +
-+        self._mgr.Update()
-+  
-+        self.SetVirtualSize(self.GetBestVirtualSize())
-+        self.Layout()
++    if(fd_cats_rasts)
++        for(i = 0; i < n_a_cats; i++)
++            if(fd_cats_rasts[i] >= 0)
++                Rast_close(fd_cats_rasts[i]);
 +
-+        return scatt
++}
 +
-+    def GetScattMgr(self):
-+        return  self.scatt_mgr
++/*!
++   \brief Compute scatter plots data.
 +
-+class CategoryListCtrl(wx.ListCtrl,
-+                       listmix.ListCtrlAutoWidthMixin,
-+                       listmix.TextEditMixin):
++    If category has not defined no category raster condition file and no scatter plot with consdtion,
++    default scatter plot is computed.
 +
-+    def __init__(self, parent, cats_mgr, id = wx.ID_ANY):
++   \param region analysis region, beaware that all input data must be prepared for this region (bands (their ranges), cats_rasts_conds rasters...)
++   \param region function calls Rast_set_window for this region
++   \param scatt_conds pointer to scScatts struct of type SC_SCATT_CONDITIONS, where are stored selected areas (conditions) in scatter plots
++   \param cats_rasts_conds paths to category raster conditions files representing selected areas (conditions) in rasters for every category 
++   \param cats_rasts_conds index in array represents corresponding category id
++   \param cats_rasts_conds for manupulation with category raster conditions file see also I_id_scatt_to_bands() and I_insert_patch_to_cat_rast()
++   \param bands names of analyzed bands, order of bands is defined by their id
++   \param n_bands number of bands
++   \param [out] scatts pointer to scScatts struct of type SC_SCATT_DATA, where are computed scatter plots stored
++   \param [out] cats_rasts array of raster maps names where will be stored all selected pixels for every category
 +
-+        wx.ListCtrl.__init__(self, parent, id,
-+                             style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES)
-+        self.columns = ((_('Class name'), 'name'),
-+                        (_('Color'), 'color'))
-+        self.Populate(columns = self.columns)
-+        
-+        self.cats_mgr = cats_mgr
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++   \return  0 on success
++   \return -1 on failure
++*/
++int I_compute_scatts(struct Cell_head *region, struct scCats * scatt_conds, const char ** cats_rasts_conds,
++                     const char ** bands, int n_bands, struct scCats * scatts, const char ** cats_rasts) 
++{
++    const char *mapset;
++    char header[1024];
 +
-+        self.rightClickedItemIdx = wx.NOT_FOUND
-+        
-+        listmix.ListCtrlAutoWidthMixin.__init__(self)
++    int fd_cats_rasts[scatt_conds->n_a_cats];
++    FILE * f_cats_rasts_conds[scatt_conds->n_a_cats];
 +
-+        listmix.TextEditMixin.__init__(self)
-+      
-+        self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnCategoryRightUp) #wxMSW
-+        self.Bind(wx.EVT_RIGHT_UP,            self.OnCategoryRightUp) #wxGTK
++    struct rast_row bands_rows[n_bands];
 +
-+        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)
++    RASTER_MAP_TYPE data_type;
 +
-+    def Update(self, **kwargs):
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++    int nrows, i_band, n_a_bands, band_id, 
++        i, i_row, head_nchars, i_cat, id_cat;
++   
++    int fd_bands[n_bands];
++    int bands_ids[n_bands];
++    int b_needed_bands[n_bands];  
 +
-+    def InitCoreCats(self):
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++    Rast_set_window(region);
 +
-+    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
++    for(i_band = 0; i_band < n_bands; i_band++)
++        fd_bands[i_band] = -1;
++    
++    for(i_band = 0; i_band < n_bands; i_band++)
++        bands_ids[i_band] = -1;
 +
-+        cat_id = self.cats_mgr.GetCategories()[row]
++    if (n_bands != scatts->n_bands ||
++        n_bands != scatt_conds->n_bands)
++        return -1;
 +
-+        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
++    memset(b_needed_bands, 0, (size_t)n_bands * sizeof(int));
 +
-+        self.SetColumnWidth(0, 100)
-+        self.SetColumnWidth(1, 100)
-+        
-+    def AddCategory(self):
++    get_needed_bands(scatt_conds, &b_needed_bands[0]);
++    get_needed_bands(scatts, &b_needed_bands[0]);
 +
-+        self.cats_mgr.addedCategory.disconnect(self.Update)
-+        cat_id = self.cats_mgr.AddCategory()
-+        self.cats_mgr.addedCategory.connect(self.Update)
++    n_a_bands = 0;
 +
-+        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)
++    /* open band rasters, which are needed for computation */
++    for(band_id = 0; band_id < n_bands; band_id++)
++    {
++        if(b_needed_bands[band_id])
++        {
++            G_debug(3, "Opening raster no. %d with name: %s", band_id, bands[band_id]);
 +
-+            self.cats_mgr.deletedCategory.disconnect(self.Update)
-+            self.cats_mgr.DeleteCategory(cat_id)
-+            self.cats_mgr.deletedCategory.connect(self.Update)
++            if ((mapset = G_find_raster2(bands[band_id],"")) == NULL) {
++                free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, 
++                                         bands_ids, NULL, NULL, scatt_conds->n_a_cats);
++                G_warning(_("Unbale to read find raster <%s>"), bands[band_id]);
++                return -1;
++            }
 +            
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+        
-+    def OnSel(self, event): 
-+        event.Skip()
++            if ((fd_bands[n_a_bands] = Rast_open_old(bands[band_id], mapset)) < 0) {
++                free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, 
++                                         bands_ids, NULL, NULL, scatt_conds->n_a_cats);
++                G_warning(_("Unbale to open raster <%s>"), bands[band_id]);
++                return -1;
++            }
 +
-+    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        
++            data_type = Rast_get_map_type(fd_bands[n_a_bands]);
++            if(data_type != CELL_TYPE) {
++                G_warning(_("Raster <%s> type is not <%s>"), bands[band_id], "CELL");
++                return -1;
++            }
 +
-+    def OnEdit(self, event):
-+        currentItem = event.m_itemIndex
-+        currentCol = event.m_col
++            bands_rows[band_id].row =  Rast_allocate_c_buf();
++            bands_rows[band_id].null_row =  Rast_allocate_null_buf();
 +
-+        if currentCol == 1:
-+            dlg = wx.ColourDialog(self)
-+            dlg.GetColourData().SetChooseFull(True)
++            if(Rast_read_range(bands[band_id], mapset, &bands_rows[band_id].rast_range) != 1){
++                free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, 
++                                         bands_ids, NULL, NULL, scatt_conds->n_a_cats);
++                G_warning(_("Unable to read range of raster <%s>"), bands[band_id]);
++                return -1;
++            }      
 +
-+            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]
++            bands_ids[n_a_bands] = band_id;
++            ++n_a_bands;
++        }
++    }
 +
-+        return self.cats_mgr.GetCategoryAttrs(cat_id)[attr]
++    /* open category rasters condition files and category rasters */
++    for(i_cat = 0; i_cat < scatts->n_a_cats; i_cat++)
++    {
++        id_cat = scatts->cats_ids[i_cat];
++        if(cats_rasts[id_cat]) {
++            fd_cats_rasts[i_cat] = Rast_open_new(cats_rasts[id_cat], CELL_TYPE);   
++        }
++        else
++            fd_cats_rasts[i_cat] = -1;
 +
-+    def OnGetItemImage(self, item):
-+        return -1
++        if(cats_rasts_conds[id_cat]) {
++            f_cats_rasts_conds[i_cat] = fopen(cats_rasts_conds[id_cat], "r");
++            if(!f_cats_rasts_conds[i_cat]) {
++                free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, bands_ids, 
++                                         f_cats_rasts_conds, f_cats_rasts_conds, scatt_conds->n_a_cats);
++                G_warning(_("Unable to open category raster condtition file <%s>"), bands[band_id]);
++                return -1;
++            }
++        }
++        else
++            f_cats_rasts_conds[i_cat] = NULL;
++    }
 +
-+    def OnGetItemAttr(self, item):
-+        return None
++    head_nchars =  get_cat_rast_header(region, header);
++    for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
++        if(f_cats_rasts_conds[i_cat])
++            if( fseek(f_cats_rasts_conds[i_cat] , head_nchars, SEEK_SET) != 0) {
++                G_warning(_("Corrupted category raster conditions file (fseek failed)"));
++                return -1;
++            }
 +
-+    def OnCategoryRightUp(self, event):
-+        """!Show context menu on right click"""
-+        item, flags = self.HitTest((event.GetX(), event.GetY()))
-+        if item != wx.NOT_FOUND and flags & wx.LIST_HITTEST_ONITEM:
-+            self.rightClickedItemIdx = item
++    nrows = Rast_window_rows();
 +
-+        # generate popup-menu
-+        cat_idx = self.rightClickedItemIdx
++    /* analyze bands by rows */
++    for (i_row = 0; i_row < nrows; i_row++)
++    {
++        for(i_band = 0; i_band < n_a_bands; i_band++)
++        {   
++            band_id = bands_ids[i_band];
++            Rast_get_c_row(fd_bands[i_band], bands_rows[band_id].row, i_row);
++            Rast_get_null_value_row (fd_bands[i_band], bands_rows[band_id].null_row, i_row);
++        }
++        if(compute_scatts_from_chunk_row(region, scatt_conds, f_cats_rasts_conds, bands_rows, scatts, fd_cats_rasts) == -1) 
++        {
++            free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, bands_ids, fd_cats_rasts, 
++                                     f_cats_rasts_conds, scatt_conds->n_a_cats);
++            return -1;
++        }
++ 
++    }
++    free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, bands_ids, 
++                             fd_cats_rasts, f_cats_rasts_conds, scatt_conds->n_a_cats); 
++    return 0;    
++}
 +
-+        cats = self.cats_mgr.GetCategories()
-+        cat_id = cats[cat_idx]
-+        showed = self.cats_mgr.GetCategoryAttrs(cat_id)['show']
-+        
-+        menu = wx.Menu()
 +
-+        if showed:
-+            text = _("Hide")
-+        else:
-+            text = _("Show")
++int I_merge_arrays(unsigned char *  merged_arr, unsigned char *  overlay_arr, unsigned rows, unsigned cols, double alpha)
++{
++    unsigned int i_row, i_col, i_b;
++    unsigned int row_idx, col_idx, idx;
++    unsigned int c_a_i, c_a;
 +
-+        item_id = wx.NewId()
-+        menu.Append(item_id, text = text)
-+        self.Bind(wx.EVT_MENU, lambda event : self._setCatAttrs(cat_id=cat_id,
-+                                                                attrs={'show' : not showed}), 
-+                                                                id=item_id) 
-+        menu.AppendSeparator()
-+        
-+        if cat_idx != 0:
-+            item_id = wx.NewId()
-+            menu.Append(item_id, text=_("Move category up"))
-+            self.Bind(wx.EVT_MENU, self.OnMoveUp, id=item_id)
++    for(i_row = 0; i_row < rows; i_row++)
++    {
++        row_idx = i_row * cols;
++        for(i_col = 0; i_col < cols; i_col++)
++        {
++                col_idx = 4 * (row_idx + i_col);
++                idx = col_idx + 3;
 +
-+        if cat_idx != len(cats) - 1:
-+            item_id = wx.NewId()
-+            menu.Append(item_id, text=_("Move category down"))
-+            self.Bind(wx.EVT_MENU, self.OnMoveDown, id=item_id)
++                c_a = overlay_arr[idx] * alpha;
++                c_a_i = 255 - c_a;
 +
-+        menu.AppendSeparator()
-+        
-+        item_id = wx.NewId()
-+        menu.Append(item_id, text=_("Change opacity level"))
-+        self.Bind(wx.EVT_MENU, self.OnPopupOpacityLevel, id=item_id)
++                merged_arr[idx] = (c_a_i * (int)merged_arr[idx] + c_a * 255) / 255;
++                
++                for(i_b = 0; i_b < 3; i_b++)
++                {
++                    idx = col_idx + i_b;
++                    merged_arr[idx] = (c_a_i * (int)merged_arr[idx] + c_a * (int)overlay_arr[idx]) / 255;
++                }
++        }
++    }
++    return 0; 
++}
 +
-+        item_id = wx.NewId()
-+        menu.Append(item_id, text=_("Export raster"))
-+        self.Bind(wx.EVT_MENU, self.OnExportCatRast, id=item_id)
 +
++int I_apply_colormap(unsigned char * vals, unsigned char * vals_mask, unsigned vals_size, unsigned char * colmap, unsigned char * col_vals){
++    unsigned int i_val;
++    int v, i, i_cm;
 +
-+        self.PopupMenu(menu)
-+        menu.Destroy()
++    for(i_val = 0; i_val < vals_size; i_val++){
++        i_cm = 4 * i_val;
 +
-+    def OnExportCatRast(self, event):
-+        """!Export training areas"""
-+        #TODO
-+        #   GMessage(parent=self, message=_("No class raster to export."))
-+        #    return
++        v = vals[i_val];
 +
-+        cat_idx = self.rightClickedItemIdx
-+        cat_id = self.cats_mgr.GetCategories()[cat_idx]
++        if(vals_mask[i_val])
++            for(i = 0; i < 4; i++) col_vals[i_cm + i] = colmap[258 * 4 + i];
++        else if(v > 255)
++            for(i = 0; i < 4; i++) col_vals[i_cm + i] = colmap[257 * 4 + i];
++        else if(v < 0)
++            for(i = 0; i < 4; i++) col_vals[i_cm + i] = colmap[256 * 4 + i];
++        else
++            for(i = 0; i < 4; i++){ col_vals[i_cm + i] = colmap[v * 4 + i];
++        }
++    }
++    return 0;
++}
+Index: lib/imagery/scatt_sccats.c
+===================================================================
+--- lib/imagery/scatt_sccats.c	(revision 0)
++++ lib/imagery/scatt_sccats.c	(working copy)
+@@ -0,0 +1,405 @@
++/*!
++   \file lib/imagery/scatt_cat_rast.c
 +
-+        self.cats_mgr.ExportCatRast(cat_id)
++   \brief Imagery library - functions for manipulation with scatter plot structs.
 +
-+    def OnMoveUp(self, event):
-+        cat_idx = self.rightClickedItemIdx
-+        cat_id = self.cats_mgr.GetCategories()[cat_idx]
-+        self.cats_mgr.ChangePosition(cat_id, cat_idx - 1)
-+        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++   Copyright (C) 2013 by the GRASS Development Team
 +
-+    def OnMoveDown(self, event):
-+        cat_idx = self.rightClickedItemIdx
-+        cat_id = self.cats_mgr.GetCategories()[cat_idx]
-+        self.cats_mgr.ChangePosition(cat_id, cat_idx + 1)
-+        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++   This program is free software under the GNU General Public License
++   (>=v2).  Read the file COPYING that comes with GRASS for details.
 +
-+    def OnPopupOpacityLevel(self, event):
-+        """!Popup opacity level indicator"""
++   \author Stepan Turek <stepan.turek at seznam.cz> (Mentor: Martin Landa)
++ */
 +
-+        cat_id = self.cats_mgr.GetCategories()[self.rightClickedItemIdx]
-+        cat_attrs = self.cats_mgr.GetCategoryAttrs(cat_id)
-+        value = cat_attrs['opacity'] * 100
-+        name = cat_attrs['name']
++#include <grass/raster.h>
++#include <grass/imagery.h>
++#include <grass/gis.h>
 +
-+        dlg = SetOpacityDialog(self, opacity = value,
-+                               title = _("Change opacity of class <%s>" % name))
++#include <stdio.h>
++#include <stdlib.h>
++#include <math.h>
++#include <string.h>
 +
-+        dlg.applyOpacity.connect(lambda value:
-+                                 self._setCatAttrs(cat_id=cat_id, attrs={'opacity' : value}))
-+        dlg.CentreOnParent()
++/*!
++   \brief Compute band ids from scatter plot id.
 +
-+        if dlg.ShowModal() == wx.ID_OK:
-+            self._setCatAttrs(cat_id=cat_id, attrs={'opacity' : value})
-+        
-+        dlg.Destroy()
++    Scatter plot id describes which bands defines the scatter plot.
 +
-+    def _setCatAttrs(self, cat_id, attrs):
-+        self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
-+        self.cats_mgr.SetCategoryAttrs(cat_id, attrs)
-+        self.cats_mgr.setCategoryAttrs.connect(self.Update)
++    Let say we have 3 bands, their ids are 0, 1 and 2.
++    Scatter plot with id 0 consists of band 1 (b_1_id) 0 and  band 2 (b_2_id) 1.
++    All scatter plots:
++    scatt_id b_1_id b_2_id
++    0        0      1
++    1        0      2
++    2        1      2
 +
++   \param scatt_id scatter plot id
++   \param n_bands number of bands
++   \param [out] b_1_id id of band1
++   \param[out] b_2_id id of band2
 +
-+class AddScattPlotDialog(wx.Dialog):
++   \return 0
++ */
++int I_id_scatt_to_bands(const int scatt_id, const int n_bands, int * b_1_id, int * b_2_id)
++{   
++    int n_b1 = n_bands - 1;
 +
-+    def __init__(self, parent, bands, id  = wx.ID_ANY):
-+        
-+        wx.Dialog.__init__(self, parent, title = ("Add scatter plot"), id = id)
++    * b_1_id = (int) ((2 * n_b1 + 1 - sqrt((double)((2 * n_b1 + 1) * (2 * n_b1 + 1) - 8 * scatt_id))) / 2);
 +
-+        self.bands = bands
++    * b_2_id = scatt_id - ((* b_1_id) * (2 * n_b1 + 1) - (* b_1_id) * (* b_1_id)) / 2 + (* b_1_id) + 1;
 +
-+        self.scatt_id = None
++    return 0;
++}
 +
-+        self._createWidgets()
 +
-+    def _createWidgets(self):
++/*!
++   \brief Compute scatter plot id from band ids.
 +
-+        self.labels = {}
-+        self.params = {}
++    See also I_id_scatt_to_bands().
 +
-+        self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("x axis:"))
++   \param n_bands number of bands
++   \param b_1_id id of band1
++   \param b_1_id id of band2
++   \param [out] scatt_id scatter plot id
 +
-+        self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+                                     choices = self.bands,
-+                                     style = wx.CB_READONLY, size = (350, 30))
++   \return 0
++ */
++int I_bands_to_id_scatt(const int b_1_id, const int b_2_id, const int n_bands, int * scatt_id)
++{   
++    int n_b1 = n_bands - 1;
 +
-+        self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("y axis:"))
++    * scatt_id = (b_1_id * (2 * n_b1 + 1) - b_1_id * b_1_id) / 2 + b_2_id - b_1_id - 1;
 +
-+        self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+                                     choices = self.bands,
-+                                     style = wx.CB_READONLY, size = (350, 30))
++    return 0;
++}
 +
-+        # 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"))
++/*!
++   \brief Initialize structure for storing scatter plots data.
 +
-+        self._layout()
++   \param cats pointer to scCats struct 
++   \param n_bands number of bands
++   \param type SC_SCATT_DATA - stores scatter plots 
++   \param type SC_SCATT_CONDITIONS - stores selected areas in scatter plots
++ */
++void I_sc_init_cats(struct scCats * cats, int n_bands, int type)
++{
++    int i_cat;
 +
-+    def _layout(self):
++    cats->type = type;
 +
-+        border = wx.BoxSizer(wx.VERTICAL) 
-+        dialogSizer = wx.BoxSizer(wx.VERTICAL)
++    cats->n_cats = 100;
++    cats->n_a_cats = 0;
 +
-+        regionSizer = wx.BoxSizer(wx.HORIZONTAL)
++    cats->n_bands = n_bands;
++    cats->n_scatts = (n_bands - 1) * n_bands / 2;
 +
-+        dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label, 
-+                                                    sel = self.band_1_ch))
++    cats->cats_arr = (struct scScatts **) G_malloc(cats->n_cats * sizeof(struct scScatts *));
++    memset(cats->cats_arr, 0, cats-> n_cats * sizeof(struct scScatts *));
 +
-+        dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label, 
-+                                                    sel = self.band_2_ch))
++    cats->cats_ids = (int *)  G_malloc(cats->n_cats * sizeof(int));
++    cats->cats_idxs =(int *)  G_malloc(cats->n_cats * sizeof(int));
 +
-+        # buttons
-+        self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
++    for(i_cat = 0; i_cat < cats->n_cats; i_cat++)
++        cats->cats_idxs[i_cat] = -1;
 +
-+        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)
++    return;
++}
 +
-+        dialogSizer.Add(item = self.btnsizer, proportion = 0,
-+                        flag = wx.ALIGN_CENTER)
++/*!
++   \brief Free data of struct scCats, the structure itself remains alocated.
 +
-+        border.Add(item = dialogSizer, proportion = 0,
-+                   flag = wx.ALL, border = 5)
++   \param cats pointer to existing scCats struct
++ */
++void I_sc_free_cats(struct scCats * cats)
++{
++    int i_cat;
 +
-+        self.SetSizer(border)
-+        self.Layout()
-+        self.Fit()
++    for(i_cat = 0; i_cat < cats->n_a_cats; i_cat++)
++    {        
++        if(cats->cats_arr[i_cat])
++        {   
++            G_free(cats->cats_arr[i_cat]->scatt_idxs);
++            G_free(cats->cats_arr[i_cat]->scatts_bands);
++            G_free(cats->cats_arr[i_cat]->scatts_arr);
++            G_free(cats->cats_arr[i_cat]);
++        }
++    }
 +
-+        # bindings
-+        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
-+        self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
++    G_free(cats->cats_ids);
++    G_free(cats->cats_idxs);
++    G_free(cats->cats_arr);
 +
-+    def _addSelectSizer(self, title, sel): 
-+        """!Helper layout function.
-+        """
-+        selSizer = wx.BoxSizer(orient = wx.VERTICAL)
++    cats->n_cats = 0;
++    cats->n_a_cats = 0;
++    cats->n_bands = 0;
++    cats->n_scatts = 0;
++    cats->type = -1;
 +
-+        selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
-+        selTitleSizer.Add(item = title, proportion = 1,
-+                          flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
++    return;
++}
 +
-+        selSizer.Add(item = selTitleSizer, proportion = 0,
-+                     flag = wx.EXPAND)
++#if 0
++void I_sc_get_active_categories(int * a_cats_ids, int * n_a_cats, struct scCats * cats)
++{
++    a_cats_ids = cats->cats_ids;
++    * n_a_cats = cats->n_a_cats;
++}
++#endif
 +
-+        selSizer.Add(item = sel, proportion = 1,
-+                     flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
-+                     border = 5)
++/*!
++   \brief Add category.
++    
++    Category represents group of scatter plots.
 +
-+        return selSizer
++   \param cats pointer to scCats struct
 +
-+    def OnClose(self, event):
-+        """!Close dialog
-+        """
-+        if not self.IsModal():
-+            self.Destroy()
-+        event.Skip()
++   \return assigned category id (starts with 0)
++   \return -1 if maximum nuber of categories was reached
++ */
++int I_sc_add_cat(struct scCats * cats)
++{
++    int i_scatt, i_cat_id, cat_id;
++    int n_a_cats = cats->n_a_cats;
 +
-+    def OnOk(self, event):
-+        """!
-+        """
-+        band_1 = self.band_1_ch.GetSelection()
-+        band_2 = self.band_2_ch.GetSelection()
++    if(cats->n_a_cats >= cats->n_cats)
++        return -1;
 +
++    for(i_cat_id = 0; i_cat_id < cats->n_cats; i_cat_id++)
++        if(cats->cats_idxs[i_cat_id] < 0) {
++            cat_id = i_cat_id;
++            break;
++        }
 +
-+        if 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
++    cats->cats_ids[n_a_cats] = cat_id;
++    cats->cats_idxs[cat_id] = n_a_cats;
++    
++    cats->cats_arr[n_a_cats] = (struct scScatts *) G_malloc(sizeof(struct scScatts));
 +
-+        self.scatt_id = idBandsToidScatt(band_1, band_2, len(self.bands))
++    cats->cats_arr[n_a_cats]->scatts_arr = (struct scdScattData **) G_malloc(cats->n_scatts * sizeof(struct scdScattData *));
++    memset((cats->cats_arr[n_a_cats]->scatts_arr), 0, cats->n_scatts * sizeof(struct scdScattData *));
++    
++    cats->cats_arr[n_a_cats]->n_a_scatts = 0;
 +
-+        event.Skip()
++    cats->cats_arr[n_a_cats]->scatts_bands = (int *) G_malloc(cats->n_scatts * 2 * sizeof(int));
++     
++    cats->cats_arr[n_a_cats]->scatt_idxs = (int *) G_malloc(cats->n_scatts * sizeof(int));
++    for(i_scatt = 0; i_scatt < cats->n_scatts; i_scatt++)
++        cats->cats_arr[n_a_cats]->scatt_idxs[i_scatt] = -1;
++    
++    ++cats->n_a_cats;
 +
-+    def GetScattId(self):
-+        return self.scatt_id
-Index: gui/wxpython/vnet/dialogs.py
-===================================================================
---- gui/wxpython/vnet/dialogs.py	(revision 57644)
-+++ gui/wxpython/vnet/dialogs.py	(working copy)
-@@ -1218,7 +1218,7 @@
-                       pos = (row, 1))
- 
-         row += 1
--        gridSizer.Add(item = self.settings["invert_colors"], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
-+        gridSizer.Add(item=self.settings["invert_colors"], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
- 
-         gridSizer.AddGrowableCol(1)
-         styleBoxSizer.Add(item = gridSizer, flag = wx.EXPAND)
-Index: gui/wxpython/vnet/toolbars.py
-===================================================================
---- gui/wxpython/vnet/toolbars.py	(revision 57644)
-+++ gui/wxpython/vnet/toolbars.py	(working copy)
-@@ -19,9 +19,9 @@
- 
- import wx
- 
--from icon              import MetaIcon
-+from icons.icon import MetaIcon
- from gui_core.toolbars import BaseToolbar, BaseIcons
--from core.gcmd         import RunCommand
-+from core.gcmd import RunCommand
- from core.utils import _
- 
- class PointListToolbar(BaseToolbar):
-Index: gui/wxpython/Makefile
-===================================================================
---- gui/wxpython/Makefile	(revision 57644)
-+++ gui/wxpython/Makefile	(working copy)
-@@ -13,7 +13,7 @@
- 	$(wildcard animation/* core/*.py dbmgr/* gcp/*.py gmodeler/* \
- 	gui_core/*.py iclass/* lmgr/*.py location_wizard/*.py mapwin/*.py mapdisp/*.py \
- 	mapswipe/* modules/*.py nviz/*.py psmap/* rlisetup/* timeline/* 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,8 +21,9 @@
- 
- PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,animation core dbmgr gcp gmodeler \
- 	gui_core iclass lmgr location_wizard mapwin mapdisp modules nviz psmap \
--	mapswipe vdigit wxplot web_services rlisetup vnet timeline)
-+	mapswipe vdigit wxplot web_services rlisetup vnet timeline scatt_plot)
- 
++    return cat_id;
++}
 +
- DSTDIRS := $(patsubst %,$(ETCDIR)/%,icons scripts xml)
- 
- default: $(DSTFILES)
++#if 0
++int I_sc_delete_cat(struct scCats * cats, int cat_id)
++{
++    int cat_idx, i_cat;
++
++    if(cat_id < 0 || cat_id >= cats->n_cats)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++
++    G_free(cats->cats_arr[cat_idx]->scatt_idxs);
++    G_free(cats->cats_arr[cat_idx]->scatts_bands);
++    G_free(cats->cats_arr[cat_idx]->scatts_arr);
++    G_free(cats->cats_arr[cat_idx]);
++
++    for(i_cat = cat_idx; i_cat < cats->n_a_cats - 1; i_cat++)
++    {
++        cats->cats_arr[i_cat] = cats->cats_arr[i_cat + 1];
++        cats->cats_ids[i_cat] = cats->cats_ids[i_cat + 1];
++    }
++    cats->cats_idxs[cat_id] = -1; 
++
++    --cats->n_a_cats;
++    
++    return 0;
++}
++#endif
++
++/*!
++   \brief Insert scatter plot data .
++    Inserted scatt_data struct must have same type as cats struct (SC_SCATT_DATA or SC_SCATT_CONDITIONS).
++
++   \param cats pointer to scCats struct
++   \param cat_id id number of category.
++   \param scatt_id id number of scatter plot.
++
++   \return  0 on success
++   \return -1 on failure
++ */
++int I_sc_insert_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
++{
++    int band_1, band_2, cat_idx, n_a_scatts;
++    struct scScatts * scatts;
++
++    if(cat_id < 0 || cat_id >= cats->n_cats)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++
++    if(scatt_id < 0 && scatt_id >= cats->n_scatts)
++        return -1;
++
++    scatts = cats->cats_arr[cat_idx];
++    if(scatts->scatt_idxs[scatt_id] >= 0)
++        return -1;
++
++    if(!scatt_data->b_conds_arr && cats->type == SC_SCATT_CONDITIONS)
++        return -1;
++
++    if(!scatt_data->scatt_vals_arr && cats->type == SC_SCATT_DATA)
++        return -1;
++
++    n_a_scatts = scatts->n_a_scatts;
++
++    scatts->scatt_idxs[scatt_id] = n_a_scatts;
++
++    I_id_scatt_to_bands(scatt_id, cats->n_bands, &band_1, &band_2);
++
++    scatts->scatts_bands[n_a_scatts * 2] = band_1;
++    scatts->scatts_bands[n_a_scatts * 2 + 1] = band_2;
++
++    scatts->scatts_arr[n_a_scatts] = scatt_data;
++    ++scatts->n_a_scatts;
++
++    return 0;
++}
++
++#if 0
++int I_sc_remove_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
++{
++    int cat_idx, scatt_idx, n_init_scatts, i_scatt;
++    struct scScatts * scatts;
++
++    if(cat_id < 0 && cat_id >= cats->n_cats)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++
++    if(scatt_id < 0 || scatt_id >= cats->n_scatts)
++        return -1;
++
++    scatts = cats->cats_arr[cat_idx];
++    if(scatts->scatt_idxs[scatt_id] < 0)
++        return -1;
++
++    scatt_data = scatts->scatts_arr[scatt_idx];
++
++    for(i_scatt = scatt_idx; i_scatt < scatts->n_a_scatts - 1; i_scatt++)
++    {
++        scatts->scatts_arr[i_scatt] = scatts->scatts_arr[i_scatt + 1];
++        scatts->scatts_bands[i_scatt * 2] = scatts->scatts_bands[(i_scatt + 1)* 2];
++        scatts->scatts_bands[i_scatt * 2 + 1] = scatts->scatts_bands[(i_scatt + 1) * 2 + 1];
++    }
++    scatts->scatts_arr[scatts->n_a_scatts] = NULL;
++
++    scatts->scatt_idxs[scatt_id] = -1;
++
++    scatt_data = scatts->scatts_arr[scatt_id];
++    scatts->n_a_scatts--;
++
++    return 0;
++}
++
++int I_sc_set_value(struct scCats * cats, int cat_id, int scatt_id, int value_idx, int value)
++{
++    int n_a_scatts = cats->cats_arr[cat_id]->n_a_scatts;
++    int cat_idx, scatt_idx, ret;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++    
++    if(cats->cats_arr[cat_idx]->scatt_idxs[scatt_id] < 0)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    scatt_idx = cats->cats_arr[cat_idx]->scatt_idxs[scatt_id];
++
++    I_scd_set_value(cats->cats_arr[cat_idx]->scatts_arr[scatt_idx], value_idx, value);
++
++    return 0;
++}
++#endif
++
++/*!
++   \brief Insert scatter plot data.
++    
++   \param scatt_data pointer to existing struct scdScattData
++   \param type SC_SCATT_DATA for scatter plots or SC_SCATT_CONDITIONS for selected areas in scatter plot
++   \param n_vals number of data values
++   \param data array of values (unsigned char for SC_SCATT_CONDITIONS, unsigned int for SC_SCATT_DATA)
++ */
++void I_scd_init_scatt_data(struct scdScattData * scatt_data, int type, int n_vals, void * data)
++{
++    scatt_data->n_vals = n_vals;
++
++    if(type == SC_SCATT_DATA)
++    {   
++        if(data)
++            scatt_data->scatt_vals_arr = (unsigned int *) data;
++        else {
++            scatt_data->scatt_vals_arr = (unsigned int *) G_malloc(n_vals * sizeof(unsigned int));
++            memset(scatt_data->scatt_vals_arr, 0, n_vals * sizeof(unsigned int)); 
++        }
++        scatt_data->b_conds_arr = NULL;
++    }
++    else if(type == SC_SCATT_CONDITIONS)
++    {
++        if(data)
++            scatt_data->b_conds_arr = (unsigned char *) data;
++        else {
++            scatt_data->b_conds_arr = (unsigned char *) G_malloc(n_vals * sizeof(unsigned char));
++            memset(scatt_data->b_conds_arr, 0, n_vals * sizeof(unsigned char));
++        }
++        scatt_data->scatt_vals_arr = NULL;
++    }
++
++    return;
++}
++
++
++#if 0
++void I_scd_get_range_min_max(struct scdScattData * scatt_data, CELL * band_1_min, CELL * band_1_max, CELL * band_2_min, CELL * band_2_max)
++{
++
++    Rast_get_range_min_max(&(scatt_data->band_1_range), band_1_min, band_2_min);
++    Rast_get_range_min_max(&(scatt_data->band_2_range), band_2_min, band_2_max);
++
++    return;
++}
++s
++void * I_scd_get_data_ptr(struct scdScattData * scatt_data)
++{
++    if(!scatt_data->b_conds_arr)
++        return scatt_data->b_conds_arr;
++    else if(!scatt_data->scatt_vals_arr)
++        return scatt_data->scatt_vals_arr;
++
++    return NULL;
++}
++
++int I_scd_set_value(struct scdScattData * scatt_data, unsigned int val_idx, unsigned int val)
++{
++    if(val_idx < 0 && val_idx >  scatt_data->n_vals)
++        return -1;
++
++    if(scatt_data->b_conds_arr)
++        scatt_data->b_conds_arr[val_idx] = val;
++    else if(scatt_data->scatt_vals_arr)
++        scatt_data->scatt_vals_arr[val_idx] = val;
++    else
++        return -1;
++
++    return 0;
++}
++#endif



More information about the grass-commit mailing list