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

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Aug 29 07:49:51 PDT 2013


Author: turek
Date: 2013-08-29 07:49:51 -0700 (Thu, 29 Aug 2013)
New Revision: 57547

Modified:
   sandbox/turek/scatter_plot/testing_patch.diff
Log:
transparency support, nxutils dependency dropped

Modified: sandbox/turek/scatter_plot/testing_patch.diff
===================================================================
--- sandbox/turek/scatter_plot/testing_patch.diff	2013-08-29 14:23:58 UTC (rev 57546)
+++ sandbox/turek/scatter_plot/testing_patch.diff	2013-08-29 14:49:51 UTC (rev 57547)
@@ -1,6 +1,1183 @@
+Index: lib/vector/Vlib/open.c
+===================================================================
+--- lib/vector/Vlib/open.c	(revision 57546)
++++ 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,746 @@
++/*!
++   \file lib/imagery/scatt.c
++
++   \brief Imagery library - functions for wx Scatter Plot Tool.
++
++   Low level functions used by wx Scatter Plot Tool.
++
++   Copyright (C) 2013 by the GRASS Development Team
++
++   This program is free software under the GNU General Public License
++   (>=v2).  Read the file COPYING that comes with GRASS for details.
++
++   \author Stepan Turek <stepan.turek at seznam.cz> (Mentor: Martin Landa)
++ */
++
++#include <grass/raster.h>
++#include <grass/imagery.h>
++#include <grass/gis.h>
++#include <grass/glocale.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <math.h>
++#include <string.h>
++
++
++struct rast_row
++{
++    CELL * row;
++    char * null_row;
++    struct Range rast_range; /*Range of whole raster.*/
++};
++
++/*!
++   \brief Create pgm header.
++
++   Scatter plot internally generates pgm files. These pgms have header in format created by this function.
++    
++   \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;
++
++    unsigned char * row_data;
++
++    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 
++*/
++static int get_rows_and_cols_bounds(struct Cell_head * A,  struct Cell_head * B, struct Cell_head * A_bounds,  struct Cell_head * B_bounds)
++{
++    float ns_res, ew_res;
++
++    struct Cell_head intersec;
++
++    /* 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();
++    
++    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);
++
++        for(i_col = 0; i_col < ncols; i_col++) {
++            patch_col = patch_bounds.west + i_col;
++
++            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
++*/
++static inline void update_cat_scatt_plts(struct rast_row * bands_rows, unsigned short * belongs_pix, struct scScatts * scatts)
++{
++    int band_axis_1, band_axis_2, i_scatt, array_idx, cat_idx, i_chunk_rows_pix, max_arr_idx;
++
++    CELL * b_1_row;
++    CELL * b_2_row;
++    char * b_1_null_row,* b_2_null_row;
++    struct rast_row b_1_rast_row, b_2_rast_row;
++
++    struct Range b_1_range, b_2_range;
++    int b_1_range_size;
++
++    int row_size = Rast_window_cols();
++
++    int * scatts_bands = scatts->scatts_bands;
++
++    for(i_scatt = 0; i_scatt < scatts->n_a_scatts; i_scatt++)
++    {   
++        b_1_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;    
++}
+\ No newline at end of file
+Index: lib/imagery/scatt_sccats.c
+===================================================================
+--- lib/imagery/scatt_sccats.c	(revision 0)
++++ lib/imagery/scatt_sccats.c	(working copy)
+@@ -0,0 +1,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: include/imagery.h
 ===================================================================
---- include/imagery.h	(revision 57529)
+--- include/imagery.h	(revision 57546)
 +++ include/imagery.h	(working copy)
 @@ -135,6 +135,56 @@
      
@@ -59,22 +1236,9 @@
  #define SIGNATURE_TYPE_MIXED 1
  
  #define GROUPFILE "CURGROUP"
-Index: include/defs/vedit.h
-===================================================================
---- include/defs/vedit.h	(revision 57529)
-+++ include/defs/vedit.h	(working copy)
-@@ -33,6 +33,8 @@
- int Vedit_merge_lines(struct Map_info *, struct ilist *);
- 
- /* move.c */
-+int Vedit_move_areas(struct Map_info *, struct Map_info **, int,
-+		     		 struct ilist *, double, double, double, int, double);
- int Vedit_move_lines(struct Map_info *, struct Map_info **, int,
- 		     struct ilist *, double, double, double, int, double);
- 
 Index: include/defs/imagery.h
 ===================================================================
---- include/defs/imagery.h	(revision 57529)
+--- include/defs/imagery.h	(revision 57546)
 +++ include/defs/imagery.h	(working copy)
 @@ -110,6 +110,23 @@
  FILE *I_fopen_subgroup_ref_new(const char *, const char *);
@@ -100,6 +1264,1170 @@
  /* sig.c */
  int I_init_signatures(struct Signature *, int);
  int I_new_signature(struct Signature *);
+Index: include/defs/vedit.h
+===================================================================
+--- include/defs/vedit.h	(revision 57546)
++++ include/defs/vedit.h	(working copy)
+@@ -33,6 +33,8 @@
+ int Vedit_merge_lines(struct Map_info *, struct ilist *);
+ 
+ /* move.c */
++int Vedit_move_areas(struct Map_info *, struct Map_info **, int,
++		     		 struct ilist *, double, double, double, int, double);
+ int Vedit_move_lines(struct Map_info *, struct Map_info **, int,
+ 		     struct ilist *, double, double, double, int, double);
+ 
+Index: gui/wxpython/mapdisp/toolbars.py
+===================================================================
+--- gui/wxpython/mapdisp/toolbars.py	(revision 57546)
++++ 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 57546)
++++ 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 57546)
++++ gui/wxpython/iclass/dialogs.py	(working copy)
+@@ -333,13 +333,19 @@
+         toolbar.SetCategories(catNames = catNames, catIdx = cats)
+         if name in catNames:
+             toolbar.choice.SetStringSelection(name)
++            cat = toolbar.GetSelectedCategoryIdx()
+         elif catNames:
+             toolbar.choice.SetSelection(0)
+-            
++            cat = toolbar.GetSelectedCategoryIdx()
++        else:
++            cat = None
++
+         if toolbar.choice.IsEmpty():
+             toolbar.EnableControls(False)
+         else:
+             toolbar.EnableControls(True)
++
++        self.mapWindow.CategoryChanged(cat)
+         # don't forget to update maps, histo, ...
+         
+     def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
+Index: gui/wxpython/iclass/toolbars.py
+===================================================================
+--- gui/wxpython/iclass/toolbars.py	(revision 57546)
++++ gui/wxpython/iclass/toolbars.py	(working copy)
+@@ -46,9 +46,7 @@
+         'importAreas' : MetaIcon(img = 'layer-import',
+                             label = _('Import training areas from vector map')),
+         'addRgb' : MetaIcon(img = 'layer-rgb-add',
+-                            label = _('Add RGB map layer')),
+-        'scatt_plot'    : MetaIcon(img = 'layer-raster-analyze',
+-                                   label = _('Open Scatter Plot Tool (EXPERIMENTAL GSoC 2013)')),
++                            label = _('Add RGB map layer'))
+         }
+         
+ class IClassMapToolbar(BaseToolbar):
+@@ -117,10 +115,7 @@
+                                      ("zoomBack", icons["zoomBack"],
+                                       self.parent.OnZoomBack),
+                                      ("zoomToMap", icons["zoomExtent"],
+-                                      self.parent.OnZoomToMap),
+-                                     (None, ),
+-                                     ("scatt_plot", iClassIcons["scatt_plot"],
+-                                      self.parent.OnScatterplot)
++                                      self.parent.OnZoomToMap)
+                                     ))
+ class IClassToolbar(BaseToolbar):
+     """!IClass toolbar
+@@ -156,7 +151,7 @@
+         """!Toolbar data"""
+         icons = iClassIcons
+         return self._getToolbarData((("selectGroup", icons['selectGroup'],
+-                                      self.parent.OnAddBands),
++                                      lambda event : self.parent.AddBands()),
+                                       (None, ),
+                                       ("classManager", icons['classManager'],
+                                       self.parent.OnCategoryManager),
+Index: gui/wxpython/iclass/frame.py
+===================================================================
+--- gui/wxpython/iclass/frame.py	(revision 57546)
++++ gui/wxpython/iclass/frame.py	(working copy)
+@@ -64,6 +64,8 @@
+                                IClassExportAreasDialog, IClassMapDialog
+ from iclass.plots       import PlotPanel
+ 
++from grass.pydispatch.signal import Signal
++
+ class IClassMapFrame(DoubleMapFrame):
+     """! wxIClass main frame
+     
+@@ -114,6 +116,10 @@
+             lambda:
+             self.statusbarManager.statusbarItems['coordinates'].SetAdditionalInfo(None))
+         self.SetSize(size)
++
++        self.groupSet = Signal("IClassMapFrame.groupSet")
++        self.categoryChanged = Signal('IClassMapFrame.categoryChanged')
++
+         #
+         # Add toolbars
+         #
+@@ -177,7 +183,7 @@
+         self.dialogs['category']   = None
+         
+         # PyPlot init
+-        self.plotPanel = PlotPanel(self, stats_data = self.stats_data)
++        self.plotPanel = PlotPanel(self, giface = self._giface, stats_data = self.stats_data)
+                                    
+         self._addPanes()
+         self._mgr.Update()
+@@ -237,7 +243,7 @@
+             return False
+         
+         return vectorName
+-        
++    
+     def RemoveTempVector(self):
+         """!Removes temporary vector map with training areas"""
+         ret = RunCommand(prog = 'g.remove',
+@@ -477,7 +483,7 @@
+         
+         self.Render(self.GetFirstWindow())
+         
+-    def OnAddBands(self, event):
++    def AddBands(self):
+         """!Add imagery group"""
+         dlg = IClassGroupDialog(self, group = self.group)
+         if dlg.ShowModal() == wx.ID_OK:
+@@ -488,7 +494,8 @@
+         """!Set imagery group"""
+         group = grass.find_file(name = name, element = 'group')
+         if group['name']:
+-            self.group = group['name']
++           self.group = group['name']
++           self.groupSet.emit(group = group['name'])
+         else:
+             GError(_("Group <%s> not found") % name, parent = self)
+     
+@@ -768,17 +775,20 @@
+         
+         Updates number of stddev, histograms, layer in preview display. 
+         """
+-        stat = self.stats_data.GetStatistics(currentCat)
+-        nstd = stat.nstd
+-        self.toolbars['iClass'].UpdateStddev(nstd)
+-        
+-        self.plotPanel.UpdateCategory(currentCat)
+-        self.plotPanel.OnPlotTypeSelected(None)
++        if currentCat:
++          stat = self.stats_data.GetStatistics(currentCat)
++          nstd = stat.nstd
++          self.toolbars['iClass'].UpdateStddev(nstd)
++          
++          self.plotPanel.UpdateCategory(currentCat)
++          self.plotPanel.OnPlotTypeSelected(None)
+                                    
+-        name = stat.rasterName
+-        name = self.previewMapManager.GetAlias(name)
+-        if name:
+-            self.previewMapManager.SelectLayer(name)
++          name = stat.rasterName
++          name = self.previewMapManager.GetAlias(name)
++          if name:
++              self.previewMapManager.SelectLayer(name)
++
++        self.categoryChanged.emit(cat = currentCat)
+         
+     def DeleteAreas(self, cats):
+         """!Removes all training areas of given categories
+@@ -1105,27 +1115,6 @@
+         self.GetFirstWindow().SetModePointer()
+         self.GetSecondWindow().SetModePointer()
+ 
+-    def OnScatterplot(self, event):
+-        """!Init interactive scatterplot tools
+-        """
+-        if self.dialogs['scatt_plot']:
+-            self.dialogs['scatt_plot'].Raise()
+-            return
+-
+-        try:
+-          from scatt_plot.dialogs import ScattPlotMainDialog
+-        except:
+-          GError(parent  = self, message = _("The Scatter Plot Tool is not installed."))
+-          return
+-
+-        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface, iclass_mapwin = self.GetFirstWindow())
+-
+-        scatt_mgr = self.dialogs['scatt_plot'].GetScattMgr()
+-        scatt_mgr.DigitDataChanged(self.toolbars['vdigit'].mapLayer.GetName(), self.GetFirstWindow().GetDigit())
+-
+-        self.dialogs['scatt_plot'].CenterOnScreen()
+-        self.dialogs['scatt_plot'].Show()
+-
+ class MapManager:
+     """! Class for managing map renderer.
+     
+Index: gui/wxpython/iclass/plots.py
+===================================================================
+--- gui/wxpython/iclass/plots.py	(revision 57546)
++++ gui/wxpython/iclass/plots.py	(working copy)
+@@ -28,7 +28,7 @@
+     for each band and for one category. Coincidence plots show min max range
+     of classes for each band.
+     """
+-    def __init__(self, parent, stats_data):
++    def __init__(self, parent, giface, stats_data):
+         scrolled.ScrolledPanel.__init__(self, parent)
+         
+         self.SetupScrolling(scroll_x = False, scroll_y = True)
+@@ -38,26 +38,64 @@
+         self.stats_data = stats_data
+         self.currentCat = None
+         
++        self._giface = giface
++
+         self.mainSizer = wx.BoxSizer(wx.VERTICAL)
+-        
++
+         self._createControlPanel()
+-        
++        self._createPlotPanel()
++        self._createScatterPlotPanel()
++
+         self.SetSizer(self.mainSizer)
+         self.mainSizer.Fit(self)
+         self.Layout()
+-        
++
++    def _createPlotPanel(self):
++
++        self.canvasPanel = wx.Panel(parent=self)
++        self.mainSizer.Add(item = self.canvasPanel, proportion = 1, flag = wx.EXPAND, border = 0)
++        self.canvasSizer = wx.BoxSizer(wx.VERTICAL)
++        self.canvasPanel.SetSizer(self.canvasSizer)
++
+     def _createControlPanel(self):
+         self.plotSwitch = wx.Choice(self, id = wx.ID_ANY,
+                                      choices = [_("Histograms"),
+-                                                _("Coincident plots")])
++                                                _("Coincident plots"),
++                                                _("Scatter plots")])
+         self.mainSizer.Add(self.plotSwitch, proportion = 0, flag = wx.EXPAND|wx.ALL, border = 5)
+         self.plotSwitch.Bind(wx.EVT_CHOICE, self.OnPlotTypeSelected)
+-        
++    
++    def _createScatterPlotPanel(self):
++        """!Init interactive scatterplot tools
++        """
++        try:
++            from scatt_plot.frame import IClassScatterPlotsPanel
++            self.scatt_plot_panel = IClassScatterPlotsPanel(parent=self, giface=self._giface, iclass_mapwin = self.parent.GetFirstWindow())
++            self.mainSizer.Add(self.scatt_plot_panel, proportion = 1, flag = wx.EXPAND, border = 0)
++            self.scatt_plot_panel.Hide()
++        except ImportError as e:#TODO
++            print "ahoj"
++            print e
++            self.scatt_plot_panel = None
++
+     def OnPlotTypeSelected(self, event):
+         """!Plot type selected"""
++
++        if self.plotSwitch.GetSelection() in [0, 1]:
++            self.SetupScrolling(scroll_x = False, scroll_y = True)
++            self.scatt_plot_panel.Hide()
++            self.canvasPanel.Show()
++            self.Layout()
++
++        elif self.plotSwitch.GetSelection() == 2:
++            self.SetupScrolling(scroll_x = False, scroll_y = False)
++            self.scatt_plot_panel.Show()
++            self.canvasPanel.Hide()
++            self.Layout()
++
+         if self.currentCat is None:
+             return
+-        
++
+         if self.plotSwitch.GetSelection() == 0:
+             stat = self.stats_data.GetStatistics(self.currentCat)
+             if not stat.IsReady():
+@@ -66,7 +104,10 @@
+             self.DrawHistograms(stat)
+         else:
+             self.DrawCoincidencePlots()
+-            
++
++        self.Layout()
++
++
+     def StddevChanged(self):
+         """!Standard deviation multiplier changed, redraw histograms"""
+         if self.plotSwitch.GetSelection() == 0:
+@@ -89,7 +130,7 @@
+             panel.Destroy()
+             
+         self.canvasList = []
+-            
++
+     def ClearPlots(self):
+         """!Clears plot canvases"""
+         for bandIdx in range(len(self.bandList)):
+@@ -104,15 +145,15 @@
+     def CreatePlotCanvases(self):
+         """!Create plot canvases according to the number of bands"""
+         for band in self.bandList:
+-            canvas = plot.PlotCanvas(self)
++            canvas = plot.PlotCanvas(self.canvasPanel)
+             canvas.SetMinSize((-1, 140))
+             canvas.SetFontSizeTitle(10)
+             canvas.SetFontSizeAxis(8)
+             self.canvasList.append(canvas)
+             
+-            self.mainSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
+-
+-        self.SetVirtualSize(self.GetBestVirtualSize()) 
++            self.canvasSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
++        
++        self.SetVirtualSize(self.GetBestVirtualSize())
+         self.Layout()
+         
+     def UpdatePlots(self, group, currentCat, stats_data):
+@@ -138,7 +179,7 @@
+         
+     def UpdateCategory(self, cat):
+         self.currentCat = cat
+-        
++    
+     def DrawCoincidencePlots(self):
+         """!Draw coincidence plots"""
+         for bandIdx in range(len(self.bandList)):
+Index: gui/wxpython/scatt_plot/scatt_core.py
+===================================================================
+--- gui/wxpython/scatt_plot/scatt_core.py	(revision 0)
++++ gui/wxpython/scatt_plot/scatt_core.py	(working copy)
+@@ -0,0 +1,785 @@
++"""!
++ at package scatt_plot.scatt_plot
++
++ at brief Non GUI functions.
++
++Classes:
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++import os
++import sys
++
++import Image
++import time
++
++import numpy as np
++#TODO
++from matplotlib.path import Path 
++
++from math import sqrt, ceil, floor
++from copy import deepcopy
++
++from grass.script   import core as grass
++from core.gcmd import GException, GError, RunCommand
++
++import grass.script as grass
++
++from core_c import CreateCatRast, ComputeScatts, UpdateCatRast, \
++                   SC_SCATT_DATA, SC_SCATT_CONDITIONS
++
++class Core:
++    def __init__(self):
++        
++        self.an_data = AnalyzedData()
++
++        self.scatts_dt = ScattPlotsData(self.an_data)
++        self.scatt_conds_dt = ScattPlotsCondsData(self.an_data)
++
++        self.cat_rast_updater = CatRastUpdater(self.scatts_dt, self.an_data, self)
++
++    def SetData(self, bands):
++        self.an_data.Create(bands)
++
++        n_bands = len(self.GetBands())
++
++        self.scatts_dt.Create(n_bands)
++        self.scatt_conds_dt.Create(n_bands)
++
++    def AddCategory(self, cat_id):
++        self.scatts_dt.AddCategory(cat_id)
++        return self.scatt_conds_dt.AddCategory(cat_id)
++
++    def DeleteCategory(self, cat_id):
++        self.scatts_dt.DeleteCategory(cat_id)
++        self.scatt_conds_dt.DeleteCategory(cat_id)
++
++    def CleanUp(self):
++        self.scatts_dt.CleanUp()
++        self.scatt_conds_dt.CleanUp()
++
++    def GetBands(self):
++        return self.an_data.GetBands()
++
++    def GetScattsData(self):
++        return self.scatts_dt;
++
++    def GetRegion(self):
++        return self.an_data.GetRegion()
++
++    def GetCatRast(self, cat_id):
++        return self.scatts_dt.GetCatRast(cat_id)
++
++    def AddScattPlot(self, scatt_id):
++    
++        self.scatts_dt.AddScattPlot(scatt_id = scatt_id)
++
++        cats_ids = self.scatts_dt.GetCategories()
++        self.ComputeCatsScatts(cats_ids)
++
++
++    def SetEditCatData(self, cat_id, scatt_id, bbox, value):
++
++        if cat_id not in self.scatts_dt.GetCategories():
++            raise GException(_("Select category for editing."))
++
++        if self.scatt_conds_dt.AddScattPlot(cat_id, scatt_id) < 0:
++            return None
++
++        arr = self.scatt_conds_dt.GetValuesArr(cat_id, scatt_id)
++
++        for k, v in bbox.iteritems():
++            bbox[k] = self._validExtend(v)
++
++        arr[bbox['btm_y'] : bbox['up_y'], bbox['btm_x'] : bbox['up_x']] = value
++        arr.flush()
++        #del arr
++
++        start_time = time.clock()
++        self.ComputeCatsScatts([cat_id])
++        #print "time"
++        #print time.clock() - start_time
++        return cat_id
++
++    def ComputeCatsScatts(self, cats_ids):
++
++        requested_dt = {}
++        requested_dt_conds = {}
++
++        for c in cats_ids:
++            requested_dt_conds[c] = self.scatt_conds_dt.GetCatScatts(c)
++            requested_dt[c] = self.scatts_dt.GetCatScatts(c)
++
++        scatt_conds = self.scatt_conds_dt.GetData(requested_dt_conds)
++        scatts = self.scatts_dt.GetData(requested_dt)
++
++        bands = self.an_data.GetBands()
++
++        cats_rasts = self.scatts_dt.GetCatsRasts()
++        cats_rasts_conds = self.scatts_dt.GetCatsRastsConds()
++
++        returncode, scatts = ComputeScatts(self.an_data.GetRegion(), scatt_conds, bands,
++                                           len(self.GetBands()), scatts, cats_rasts_conds, cats_rasts)
++
++        #print "ComputeScatts"
++        #print returncode
++        if returncode < 0:
++            GException(_("Computing of scatter plots failed."))
++        #self.scatts_dt.SetData(scatts)
++
++    def CatRastUpdater(self):
++        return self.cat_rast_updater
++    
++    def UpdateCategoryWithPolygons(self, cat_id, scatts_pols, value):
++        
++        if cat_id not in self.scatts_dt.GetCategories():
++            raise GException(_("Select category for editing."))
++
++        for scatt_id, coords in scatts_pols.iteritems():
++
++            if self.scatt_conds_dt.AddScattPlot(cat_id, scatt_id) < 0:
++                return False
++
++            b1, b2 = idScattToidBands(scatt_id, len(self.an_data.GetBands()))
++
++            b1_info = self.an_data.GetBandInfo(b1)
++            b2_info = self.an_data.GetBandInfo(b2)
++
++            raster_pol = RasterizePolygon(coords, b1_info['range'], b2_info['range'])
++            
++            rescaled = (255.0 / raster_pol.max() * (raster_pol - raster_pol.min())).astype(np.uint8)
++
++            im = Image.fromarray(rescaled)
++            im.save('/home/ostepok/Desktop/obrazek.png')
++            
++            raster_ind = np.where(raster_pol > 0) 
++            arr = self.scatt_conds_dt.GetValuesArr(cat_id, scatt_id)
++
++            arr[raster_ind] = value
++            arr.flush()
++
++        rescaled = (255.0 / arr.max() * (arr - arr.min())).astype(np.uint8)
++        im = Image.fromarray(rescaled)
++        im.save('/home/ostepok/Desktop/arr_obrazek.png')
++
++        self.ComputeCatsScatts([cat_id])
++
++        return cat_id
++
++    def _validExtend(self, val):
++        #TODO do it general
++        if  val > 255:
++            val = 255
++        elif val < 0:
++            val = 0
++
++        return val
++
++class CatRastUpdater:
++
++    def __init__(self, scatts_dt, an_data, core):
++        self.scatts_dt = scatts_dt
++        self.an_data = an_data # TODO may be confusing
++        self.core = core
++        self.vectMap = None
++
++    def SetVectMap(self, vectMap):
++        self.vectMap = vectMap
++
++    def EditedFeature(self, new_bboxs, new_areas_cats, old_bboxs, old_areas_cats):
++        #TODO possible optimization - bbox only of vertex and its two neighbours
++
++        bboxs = old_bboxs + new_bboxs
++        areas_cats = old_areas_cats + new_areas_cats 
++
++        updated_cats = []
++
++        for i in range(len(areas_cats)):
++            self._updateCatRast(bboxs[i], areas_cats[i], updated_cats)
++        
++        return updated_cats
++
++    def _updateCatRast(self, bbox, areas_cats, updated_cats):
++
++        rasterized_cats = []
++        for c in range(len(areas_cats)):
++
++            if not areas_cats[c]:
++                continue
++
++            layer = areas_cats[c].keys()[0]
++            cat =  areas_cats[c][layer][0]
++
++            if cat in rasterized_cats:
++                continue
++
++            rasterized_cats.append(cat)
++            updated_cats.append(cat)
++
++            grass_region = self._create_grass_region_env(bbox)
++
++            #TODO hack
++            patch_rast = "temp_scatt_patch"
++            self._rasterize(grass_region, layer, cat, patch_rast)
++
++            region = self.an_data.GetRegion()
++            ret = UpdateCatRast(patch_rast, region, self.scatts_dt.GetCatRastCond(cat))
++            if ret < 0:
++                GException(_("Patching category raster conditions file failed."))            
++            RunCommand("g.remove",
++                      rast = patch_rast)
++
++    def _rasterize(self, grass_region, layer, cat, out_rast):
++
++        #TODO different thread may be problem when user edits map
++        environs = os.environ.copy()
++        environs['GRASS_VECTOR_TEMPORARY'] = '1'
++
++        ret, text, msg = RunCommand("v.build",
++                                      map = self.vectMap,
++                                      getErrorMsg = True,
++                                      read = True,
++                                      env = environs)
++
++        if ret != 0:
++            GException(_("v.build failed:\n%s" % msg))
++
++        environs = os.environ.copy()
++        environs["GRASS_REGION"] = grass_region["GRASS_REGION"]
++        environs['GRASS_VECTOR_TEMPORARY'] = '1'
++
++        ret, text, msg = RunCommand("v.to.rast",
++                                    input = self.vectMap,
++                                    use = "cat",
++                                    layer = str(layer),
++                                    cat = str(cat),
++                                    output = out_rast,
++                                    getErrorMsg = True,
++                                    read = True,
++                                    overwrite = True,
++                                    env = environs)
++
++        if ret != 0:
++            GException(_("v.to.rast failed:\n%s" % msg))
++
++    def _create_grass_region_env(self, bbox):
++
++        region = self.an_data.GetRegion()
++        new_region = {}
++
++        if bbox["maxy"] <= region["s"]:
++            return 0
++        elif bbox["maxy"] >= region["n"]:
++            new_region["n"] = bbox["maxy"]
++        else:
++            new_region["n"] = ceil((bbox["maxy"] - region["s"]) / region["nsres"]) * region["nsres"] + region["s"]
++
++        if bbox["miny"] >= region["n"]:
++            return 0
++        elif bbox["miny"] <= region["s"]:
++            new_region["s"] = bbox["miny"]
++        else:
++            new_region["s"] = floor((bbox["miny"] - region["s"]) / region["nsres"]) * region["nsres"] + region["s"]
++
++        if bbox["maxx"] <= region["w"]:
++            return 0
++        elif bbox["maxx"] >= region["e"]:
++            new_region["e"] = bbox["maxx"]
++        else:
++            new_region["e"] = ceil((bbox["maxx"] - region["w"]) / region["ewres"]) * region["ewres"] + region["w"]
++
++        if bbox["minx"] >= region["e"]:
++            return 0
++        elif bbox["minx"] <= region["w"]:
++            new_region["w"] = bbox["minx"]
++        else:
++            new_region["w"] = floor((bbox["minx"] - region["w"]) / region["ewres"]) * region["ewres"] + region["w"]
++
++        #TODO check regions resolutin
++        new_region["nsres"] = region["nsres"]
++        new_region["ewres"] = region["ewres"]
++
++        return {"GRASS_REGION" :  grass.region_env(**new_region)}
++
++class AnalyzedData:
++
++    def __init__(self):
++        
++        self.bands = []
++        self.bands_info = {}
++
++        self.region = None
++
++    def GetRegion(self):
++        return self.region
++
++    def Create(self, bands):
++
++        self.bands = bands
++        self.region = None
++
++        ret, region, msg = RunCommand("g.region",
++                                      flags = "gp",
++                                      getErrorMsg = True,
++                                      read = True)
++
++        if  ret != 0:
++            raise GException("g.region failed:\n%s" % msg)
++
++
++        self.bands_info = {}
++        for b in bands:
++            self.bands_info[b] = self._getRasterInfo(b)
++            if self.bands_info[b]["datatype"] != "CELL":
++                raise GException(_("Raster <%s> is not <CELL> type.") % (b))
++            #TODO size of raster check
++
++        self.region = self._parseRegion(region)
++
++    def _getRasterInfo(self, rast):
++        """
++        """
++        ret, out, msg = RunCommand("r.info",
++                                    map = rast,
++                                    flags = "rg",
++                                    getErrorMsg = True,
++                                    read = True)
++
++        if  ret != 0:
++            raise GException("r.info failed:\n%s" % msg)
++
++        out = out.split("\n")
++        raster_info = {} 
++
++        for b in out:
++            if not b.strip():
++                continue
++            k, v = b.split("=")
++            if k == "datatype":
++                pass
++            elif k in ['rows', 'cols', 'cells', 'min', 'max']:
++                v = int(v)
++            else:
++                v = float(v)
++
++            raster_info[k] = v
++
++        raster_info['range'] = raster_info['max'] - raster_info['min'] + 1
++        return raster_info
++
++    def GetBands(self):
++        return self.bands
++
++    def GetBandInfo(self, band_id):
++        band = self.bands[band_id]
++        return self.bands_info[band]
++
++    def _parseRegion(self, region_str):
++
++        region = {}
++        region_str = region_str.splitlines()
++
++        for param in region_str:
++            k, v = param.split("=")
++            if k in ["rows", "cols", "cells"]:
++                v = int(v)
++            else:
++                v = float(v)
++            region[k] = v
++
++        return region
++
++class ScattPlotsCondsData:
++
++    def __init__(self, an_data):
++
++        self.an_data = an_data
++
++        #TODO
++        self.max_n_cats = 10
++    
++        self.dtype = 'uint8'
++        self.type = 1;
++        self.CleanUp()
++
++    def CleanUp(self):
++    
++        self.cats = {}
++
++        self.n_scatts = -1
++        self.n_bands = -1
++
++        for cat_id in self.cats.keys():
++            self.DeleteCategory(cat_id)
++
++    def Create(self, n_bands):
++
++        self.CleanUp()
++
++        self.n_scatts =  (n_bands - 1) * n_bands / 2;
++        self.n_bands = n_bands
++
++        self.AddCategory(cat_id = 0)
++
++    def AddCategory(self, cat_id):
++
++        if cat_id not in self.cats.keys():
++            self.cats[cat_id] = {}
++            return cat_id
++        return -1
++
++    def DeleteCategory(self, cat_id):
++
++        if cat_id not in self.cats.keys():
++            return False
++
++        for scatt in self.cats[cat_id].itervalues():
++            del scatt['np_vals']
++
++        del self.cats[cat_id]
++
++        return True
++
++    def GetCategories(self):
++        return self.cats.keys()
++
++    def GetCatScatts(self, cat_id):
++
++        if not self.cats.has_key(cat_id):
++            return False
++
++        return self.cats[cat_id].keys()
++
++
++    def AddScattPlot(self, cat_id, scatt_id):
++
++        if not self.cats.has_key(cat_id):
++            return -1
++
++        if self.cats[cat_id].has_key(scatt_id):
++            return 0
++
++        b_i = self.GetBandsInfo(scatt_id)
++
++        shape = (b_i['b2']['max'] - b_i['b2']['min'] + 1, b_i['b1']['max'] - b_i['b1']['min'] + 1)
++
++        np_vals = np.memmap(grass.tempfile(), dtype=self.dtype, mode='w+', shape = shape)
++        np_vals.flush()
++
++        self.cats[cat_id][scatt_id] = {
++                                        'np_vals' : np_vals,
++                                      }
++
++        return 1
++
++    def GetBandsInfo(self, scatt_id):
++        b1, b2 = idScattToidBands(scatt_id, len(self.an_data.GetBands()))
++
++        b1_info = self.an_data.GetBandInfo(b1)
++        b2_info = self.an_data.GetBandInfo(b2)
++
++        bands_info = {'b1' : b1_info,
++                      'b2' : b2_info}
++
++        return bands_info
++
++    def DeleScattPlot(self, cat_id, scatt_id):
++
++        if not self.cats.has_key(cat_id):
++            return False
++
++        if not self.cats[cat_id].has_key(scatt_id):
++            return False
++
++        del self.cats[cat_id][scatt_id]
++        return True
++
++    def GetValuesArr(self, cat_id, scatt_id):
++
++        if not self.cats.has_key(cat_id):
++            return None
++
++        if not self.cats[cat_id].has_key(scatt_id):
++            return None
++
++        return self.cats[cat_id][scatt_id]['np_vals']
++
++    def GetData(self, requested_dt):
++        
++        cats = {}
++        for cat_id, scatt_ids in requested_dt.iteritems():
++            if not cats.has_key(cat_id):
++                cats[cat_id] = {}
++            for scatt_id in scatt_ids:
++                # if key is missing condition is always True (full scatter plor is computed)
++                if self.cats[cat_id].has_key(scatt_id):
++                    cats[cat_id][scatt_id] = {'np_vals' : self.cats[cat_id][scatt_id]['np_vals'],
++                                              'bands_info' : self.GetBandsInfo(scatt_id)}
++                        
++        return cats
++
++    def SetData(self, cats):
++        
++        for cat_id, scatt_ids in cats.iteritems():            
++            for scatt_id in scatt_ids:
++                # if key is missing condition is always True (full scatter plor is computed)
++                if self.cats[cat_id].has_key(scatt_id):
++                    self.cats[cat_id][scatt_id]['np_vals'] = cats[cat_id][scatt_id]['np_vals']
++                   
++class ScattPlotsData(ScattPlotsCondsData):
++
++    def __init__(self, an_data):
++
++        self.cats_rasts = {}
++        self.cats_rasts_conds = {}    
++        self.scatts_ids = []    
++
++        ScattPlotsCondsData.__init__(self, an_data)
++
++        self.dtype = 'uint32'
++
++        #TODO
++        self.type = 0
++
++    def AddCategory(self, cat_id):
++        cat_id = ScattPlotsCondsData.AddCategory(self, cat_id)
++        if cat_id < 0:
++            return cat_id
++
++        for scatt_id in self.scatts_ids:
++            ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
++
++        if cat_id == 0:
++            self.cats_rasts_conds[cat_id] = None
++            self.cats_rasts[cat_id] = None
++        else:
++            self.cats_rasts_conds[cat_id] = grass.tempfile()
++            self.cats_rasts[cat_id] = "temp_cat_rast_%d" % cat_id
++            region = self.an_data.GetRegion()
++            CreateCatRast(region, self.cats_rasts_conds[cat_id])
++
++        return cat_id
++
++    def DeleteCategory(self, cat_id):
++
++        ScattPlotsCondsData.DeleteCategory(self, cat_id)
++
++        grass.try_remove(self.cats_rasts_conds[cat_id])
++        del self.cats_rasts_conds[cat_id]
++
++        grass.try_remove(self.cats_rasts[cat_id])
++        del self.cats_rasts[cat_id]
++
++        return True
++
++    def AddScattPlot(self, scatt_id):
++        
++        if scatt_id in self.scatts_ids:
++            return False
++
++        self.scatts_ids.append(scatt_id)
++        for cat_id in self.cats.iterkeys():
++                ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
++                self.cats[cat_id][scatt_id]['ellipse'] = None
++
++        return True
++
++    def DeleteScatterPlot(self, scatt_id):
++        
++        if scatt_id not in self.scatts_ids:
++            return False
++
++        self.scatts_ids.remove(scatt_id)
++
++        for cat_id in self.cats.iterkeys():
++                ScattPlotsCondsData.DeleteScattPlot(self, cat_id, scatt_id)
++
++        return True
++
++    def GetScatt(self, scatt_id, cats_ids = None):
++        if scatt_id not in self.scatts_ids:
++            return False
++
++        scatts = {}
++        for cat_id in self.cats.iterkeys():
++            if cats_ids and cat_id not in cats_ids:
++                continue
++            scatts[cat_id] = {'np_vals' : self.cats[cat_id][scatt_id]['np_vals'],
++                              'bands_info' : self.GetBandsInfo(scatt_id)}
++        return scatts
++
++    def GetEllipses(self, scatt_id):
++        if scatt_id not in self.scatts_ids:
++            return False
++
++        scatts = {}
++        for cat_id in self.cats.iterkeys():
++            if cat_id == 0:
++                continue
++            scatts[cat_id] = self._getEllipse(cat_id, scatt_id)
++
++        return scatts
++
++    def _getEllipse(self, cat_id, scatt_id):
++        # Joe Kington
++        # http://stackoverflow.com/questions/12301071/multidimensional-confidence-intervals
++
++        nstd = 2
++        data = np.copy(self.cats[cat_id][scatt_id]['np_vals'])
++
++        sel_pts = np.where(data > 0)
++
++        x = sel_pts[1]
++        y = sel_pts[0]
++
++        flatten_data = data.reshape([-1])
++        flatten_sel_pts = np.nonzero(flatten_data)
++        weights = flatten_data[flatten_sel_pts]
++        if len(weights) == 0:
++            return None
++
++        x_avg = np.average(x, weights=weights)
++        y_avg = np.average(y, weights=weights)
++        pos = np.array([x_avg, y_avg])
++
++        x_diff = (x - x_avg)
++        y_diff = (y - y_avg)
++        
++        x_diff = (x - x_avg) 
++        y_diff = (y - y_avg) 
++
++        diffs = x_diff * y_diff.T
++        cov = np.dot(diffs, weights) / (np.sum(weights) - 1)
++
++        diffs = x_diff * x_diff.T
++        var_x = np.dot(diffs, weights) /  (np.sum(weights) - 1)
++        
++        diffs = y_diff * y_diff.T
++        var_y = np.dot(diffs, weights) /  (np.sum(weights) - 1)
++
++        cov = np.array([[var_x, cov],[cov, var_y]])
++
++        def eigsorted(cov):
++            vals, vecs = np.linalg.eigh(cov)
++            order = vals.argsort()[::-1]
++            return vals[order], vecs[:,order]
++
++        vals, vecs = eigsorted(cov)
++        theta = np.degrees(np.arctan2(*vecs[:,0][::-1]))
++
++        # Width and height are "full" widths, not radius
++        width, height = 2 * nstd * np.sqrt(vals)
++
++        ellipse = {'pos' : pos, 
++                   'width' : width,
++                   'height' : height,
++                   'theta' : theta}
++
++        del data
++        del flatten_data
++        del flatten_sel_pts
++        del weights
++        del sel_pts
++        return ellipse
++
++    def CleanUp(self):
++
++        ScattPlotsCondsData.CleanUp(self)        
++        for tmp in self.cats_rasts_conds:
++            grass.try_remove(tmp) 
++        for tmp in self.cats_rasts:
++            grass.try_remove(tmp) 
++
++        self.cats_rasts = {}
++        self.cats_rasts_conds = {}
++
++
++    def GetCatRast(self, cat_id):
++        return self.cats_rasts[cat_id]
++
++    def GetCatRastCond(self, cat_id):
++        return self.cats_rasts_conds[cat_id]
++
++    def GetCatsRastsConds(self):
++        max_cat_id = max(self.cats_rasts_conds.keys())
++
++        cats_rasts_conds = [''] * (max_cat_id + 1)
++        for i_cat_id, i_rast in self.cats_rasts_conds.iteritems():
++            cats_rasts_conds[i_cat_id] = i_rast
++
++        return cats_rasts_conds
++
++    def GetCatsRasts(self):
++        max_cat_id = max(self.cats_rasts.keys())
++
++        cats_rasts = [''] * (max_cat_id + 1)
++        for i_cat_id, i_rast in self.cats_rasts.iteritems():
++            cats_rasts[i_cat_id] = i_rast
++
++        return cats_rasts
++
++
++def RasterizePolygon(pol, height, width):
++
++    # Joe Kington
++    # http://stackoverflow.com/questions/3654289/scipy-create-2d-polygon-mask
++
++    #poly_verts = [(1,1), (1,4), (4,4),(4,1), (1,1)]
++
++    nx = width + 1
++    ny = height + 1
++
++    x, y = np.meshgrid(np.arange(nx), np.arange(ny))
++    x, y = x.flatten(), y.flatten()
++
++    points = np.vstack((x,y)).T
++
++    p = Path(pol)
++    grid = p.contains_points(points)
++    grid = grid.reshape((ny,nx))
++
++    raster = np.zeros((height, width), dtype=np.uint8)#TODO bool
++
++    #TODO this part is very inefficient, replace it with better solution
++    for (y, x), value in np.ndenumerate(grid):
++
++        if x >= width - 1: continue 
++        if y >= height - 1: continue
++
++        if grid[y, x]:
++            raster[y, x] = 1
++            raster[y + 1, x] = 1
++            raster[y, x + 1] = 1
++            raster[y + 1, x + 1] = 1
++
++    return raster
++
++#TODO move to utils?
++def idScattToidBands(scatt_id, n_bands):
++ 
++    n_b1 = n_bands - 1
++
++    band_1 = (int) ((2 * n_b1 + 1 - sqrt(((2 * n_b1 + 1) * (2 * n_b1 + 1) - 8 * scatt_id))) / 2)
++
++    band_2 = scatt_id - (band_1 * (2 * n_b1 + 1) - band_1 * band_1) / 2 + band_1 + 1
++
++    return band_1, band_2
++
++def idBandsToidScatt(band_1_id, band_2_id, n_bands):
++
++    if band_2_id <  band_1_id:
++        tmp = band_1
++        band_1_id = band_2_id
++        band_2_id = tmp
++
++    n_b1 = n_bands - 1
++
++    scatt_id = (band_1_id * (2 * n_b1 + 1) - band_1_id * band_1_id) / 2 + band_2_id - band_1_id - 1
++
++    return scatt_id
++
 Index: gui/wxpython/scatt_plot/core_c.py
 ===================================================================
 --- gui/wxpython/scatt_plot/core_c.py	(revision 0)
@@ -128,7 +2456,7 @@
 +    from grass.lib.imagery import *
 +    from grass.lib.gis import Cell_head, G_get_window
 +except ImportError, e:
-+    sys.stderr.write(_("Loading imagery lib failed"))
++    sys.stderr.write(_("Loading ctypes libs failed"))
 +
 +from core.gcmd import GException
 +
@@ -790,7 +3118,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/plots.py	(revision 0)
 +++ gui/wxpython/scatt_plot/plots.py	(working copy)
-@@ -0,0 +1,666 @@
+@@ -0,0 +1,667 @@
 +"""!
 + at package scatt_plot.dialogs
 +
@@ -807,6 +3135,7 @@
 +"""
 +import wx
 +import numpy as np
++from numpy.lib.stride_tricks import as_strided
 +import random
 +from copy import deepcopy
 +
@@ -831,10 +3160,8 @@
 +    haveMatPlot = False
 +from grass.pydispatch.signal import Signal
 +
-+
 +#class PlotImages()?
 +
-+
 +class ScatterPlotWidget(wx.Panel):
 +    def __init__(self, parent, scatt_id, scatt_mgr,
 +                 id = wx.ID_ANY):
@@ -998,14 +3325,25 @@
 +            masked_cat = masked_cat/ float(vmax)
 +
 +            colored_cat = np.uint8(cmap(masked_cat) * 255)
++            #colored_cat[...,3] = np.choose(masked_cat.mask, (255, 0))
 +            
 +            if init:
 +                merged_img = colored_cat
 +                init = False
 +            else:
-+                for i in range(4):
-+                    merged_img[...,i] = np.choose(masked_cat.mask, (colored_cat[...,i], merged_img[...,i]))
++                #c_img_a = np.memmap(grass.tempfile(), dtype="uint16", mode='w+', shape = shape) 
 +
++                c_img_a = colored_cat.astype('uint16')[:,:,3]
++                c_img_ai= 255 - colored_cat.astype('uint16')[:,:,3]
++
++                #TODO strides
++                #b = as_strided(a, strides=(0, a.strides[3], a.strides[3], a.strides[3]), shape=(3, a.shape[0], a.shape[1]))
++                for i in range(3):
++                    m_i = merged_img[:,:,i]
++                    merged_img[:,:,i] = (m_i * c_img_ai + colored_cat[:,:,i] * c_img_a) / 256;
++
++                merged_img[:,:,3] = (merged_img[:,:,3] * c_img_ai + 255 * c_img_a) / 256;
++
 +                del colored_cat
 +            del masked_cat
 +
@@ -1015,17 +3353,8 @@
 +                     interpolation='nearest',
 +                     aspect = "auto")
 +
-+        #TODO needs optimization
-+        #img = self.axes.imshow(merged_img,
-+        #                       origin = 'lower',
-+        #                       extent = self.full_extend, 
-+        #                       interpolation='nearest',
-+        #                       aspect = "auto")
-+
 +        callafter_list.append([self.axes.draw_artist, [img]])
 +
-+        #self.fig.savefig("/home/ostepok/Desktop/data.png")
-+
 +        for cat_id, e in ellipses.iteritems():
 +            if cat_id == 0 or not e:
 +                continue
@@ -2539,823 +4868,9 @@
 +
 +    def GetToolId(self, toolName):
 +        return vars(self)[toolName]            
-Index: gui/wxpython/scatt_plot/scatt_core.py
-===================================================================
---- gui/wxpython/scatt_plot/scatt_core.py	(revision 0)
-+++ gui/wxpython/scatt_plot/scatt_core.py	(working copy)
-@@ -0,0 +1,785 @@
-+"""!
-+ at package scatt_plot.scatt_plot
-+
-+ at brief Non GUI functions.
-+
-+Classes:
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+import os
-+import sys
-+
-+#TODO
-+import Image
-+import time
-+
-+import numpy as np
-+#TODO should use another function
-+from matplotlib.nxutils import points_inside_poly
-+
-+from math import sqrt, ceil, floor
-+from copy import deepcopy
-+
-+from grass.script   import core as grass
-+from core.gcmd import GException, GError, RunCommand
-+
-+import grass.script as grass
-+
-+from core_c import CreateCatRast, ComputeScatts, UpdateCatRast, \
-+                   SC_SCATT_DATA, SC_SCATT_CONDITIONS
-+
-+class Core:
-+    def __init__(self):
-+        
-+        self.an_data = AnalyzedData()
-+
-+        self.scatts_dt = ScattPlotsData(self.an_data)
-+        self.scatt_conds_dt = ScattPlotsCondsData(self.an_data)
-+
-+        self.cat_rast_updater = CatRastUpdater(self.scatts_dt, self.an_data, self)
-+
-+    def SetData(self, bands):
-+        self.an_data.Create(bands)
-+
-+        n_bands = len(self.GetBands())
-+
-+        self.scatts_dt.Create(n_bands)
-+        self.scatt_conds_dt.Create(n_bands)
-+
-+    def AddCategory(self, cat_id):
-+        self.scatts_dt.AddCategory(cat_id)
-+        return self.scatt_conds_dt.AddCategory(cat_id)
-+
-+    def DeleteCategory(self, cat_id):
-+        self.scatts_dt.DeleteCategory(cat_id)
-+        self.scatt_conds_dt.DeleteCategory(cat_id)
-+
-+    def CleanUp(self):
-+        self.scatts_dt.CleanUp()
-+        self.scatt_conds_dt.CleanUp()
-+
-+    def GetBands(self):
-+        return self.an_data.GetBands()
-+
-+    def GetScattsData(self):
-+        return self.scatts_dt;
-+
-+    def GetRegion(self):
-+        return self.an_data.GetRegion()
-+
-+    def GetCatRast(self, cat_id):
-+        return self.scatts_dt.GetCatRast(cat_id)
-+
-+    def AddScattPlot(self, scatt_id):
-+    
-+        self.scatts_dt.AddScattPlot(scatt_id = scatt_id)
-+
-+        cats_ids = self.scatts_dt.GetCategories()
-+        self.ComputeCatsScatts(cats_ids)
-+
-+
-+    def SetEditCatData(self, cat_id, scatt_id, bbox, value):
-+
-+        if cat_id not in self.scatts_dt.GetCategories():
-+            raise GException(_("Select category for editing."))
-+
-+        if self.scatt_conds_dt.AddScattPlot(cat_id, scatt_id) < 0:
-+            return None
-+
-+        arr = self.scatt_conds_dt.GetValuesArr(cat_id, scatt_id)
-+
-+        for k, v in bbox.iteritems():
-+            bbox[k] = self._validExtend(v)
-+
-+        arr[bbox['btm_y'] : bbox['up_y'], bbox['btm_x'] : bbox['up_x']] = value
-+        arr.flush()
-+        #del arr
-+
-+        start_time = time.clock()
-+        self.ComputeCatsScatts([cat_id])
-+        #print "time"
-+        #print time.clock() - start_time
-+        return cat_id
-+
-+    def ComputeCatsScatts(self, cats_ids):
-+
-+        requested_dt = {}
-+        requested_dt_conds = {}
-+
-+        for c in cats_ids:
-+            requested_dt_conds[c] = self.scatt_conds_dt.GetCatScatts(c)
-+            requested_dt[c] = self.scatts_dt.GetCatScatts(c)
-+
-+        scatt_conds = self.scatt_conds_dt.GetData(requested_dt_conds)
-+        scatts = self.scatts_dt.GetData(requested_dt)
-+
-+        bands = self.an_data.GetBands()
-+
-+        cats_rasts = self.scatts_dt.GetCatsRasts()
-+        cats_rasts_conds = self.scatts_dt.GetCatsRastsConds()
-+
-+        returncode, scatts = ComputeScatts(self.an_data.GetRegion(), scatt_conds, bands,
-+                                           len(self.GetBands()), scatts, cats_rasts_conds, cats_rasts)
-+
-+        #print "ComputeScatts"
-+        #print returncode
-+        if returncode < 0:
-+            GException(_("Computing of scatter plots failed."))
-+        #self.scatts_dt.SetData(scatts)
-+
-+    def CatRastUpdater(self):
-+        return self.cat_rast_updater
-+    
-+    def UpdateCategoryWithPolygons(self, cat_id, scatts_pols, value):
-+        
-+        if cat_id not in self.scatts_dt.GetCategories():
-+            raise GException(_("Select category for editing."))
-+
-+        for scatt_id, coords in scatts_pols.iteritems():
-+
-+            if self.scatt_conds_dt.AddScattPlot(cat_id, scatt_id) < 0:
-+                return False
-+
-+            b1, b2 = idScattToidBands(scatt_id, len(self.an_data.GetBands()))
-+
-+            b1_info = self.an_data.GetBandInfo(b1)
-+            b2_info = self.an_data.GetBandInfo(b2)
-+
-+            raster_pol = RasterizePolygon(coords, b1_info['range'], b2_info['range'])
-+            
-+            rescaled = (255.0 / raster_pol.max() * (raster_pol - raster_pol.min())).astype(np.uint8)
-+
-+            im = Image.fromarray(rescaled)
-+            im.save('/home/ostepok/Desktop/obrazek.png')
-+            
-+            raster_ind = np.where(raster_pol > 0) 
-+            arr = self.scatt_conds_dt.GetValuesArr(cat_id, scatt_id)
-+
-+            arr[raster_ind] = value
-+            arr.flush()
-+
-+        rescaled = (255.0 / arr.max() * (arr - arr.min())).astype(np.uint8)
-+        im = Image.fromarray(rescaled)
-+        im.save('/home/ostepok/Desktop/arr_obrazek.png')
-+
-+        self.ComputeCatsScatts([cat_id])
-+
-+        return cat_id
-+
-+    def _validExtend(self, val):
-+        #TODO do it general
-+        if  val > 255:
-+            val = 255
-+        elif val < 0:
-+            val = 0
-+
-+        return val
-+
-+class CatRastUpdater:
-+
-+    def __init__(self, scatts_dt, an_data, core):
-+        self.scatts_dt = scatts_dt
-+        self.an_data = an_data # TODO may be confusing
-+        self.core = core
-+        self.vectMap = None
-+
-+    def SetVectMap(self, vectMap):
-+        self.vectMap = vectMap
-+
-+    def EditedFeature(self, new_bboxs, new_areas_cats, old_bboxs, old_areas_cats):
-+        #TODO possible optimization - bbox only of vertex and its two neighbours
-+
-+        bboxs = old_bboxs + new_bboxs
-+        areas_cats = old_areas_cats + new_areas_cats 
-+
-+        updated_cats = []
-+
-+        for i in range(len(areas_cats)):
-+            self._updateCatRast(bboxs[i], areas_cats[i], updated_cats)
-+        
-+        return updated_cats
-+
-+    def _updateCatRast(self, bbox, areas_cats, updated_cats):
-+
-+        rasterized_cats = []
-+        for c in range(len(areas_cats)):
-+
-+            if not areas_cats[c]:
-+                continue
-+
-+            layer = areas_cats[c].keys()[0]
-+            cat =  areas_cats[c][layer][0]
-+
-+            if cat in rasterized_cats:
-+                continue
-+
-+            rasterized_cats.append(cat)
-+            updated_cats.append(cat)
-+
-+            grass_region = self._create_grass_region_env(bbox)
-+
-+            #TODO hack
-+            patch_rast = "temp_scatt_patch"
-+            self._rasterize(grass_region, layer, cat, patch_rast)
-+
-+            region = self.an_data.GetRegion()
-+            ret = UpdateCatRast(patch_rast, region, self.scatts_dt.GetCatRastCond(cat))
-+            if ret < 0:
-+                GException(_("Patching category raster conditions file failed."))            
-+            RunCommand("g.remove",
-+                      rast = patch_rast)
-+
-+    def _rasterize(self, grass_region, layer, cat, out_rast):
-+
-+        #TODO different thread may be problem when user edits map
-+        environs = os.environ.copy()
-+        environs['GRASS_VECTOR_TEMPORARY'] = '1'
-+
-+        ret, text, msg = RunCommand("v.build",
-+                                      map = self.vectMap,
-+                                      getErrorMsg = True,
-+                                      read = True,
-+                                      env = environs)
-+
-+        if ret != 0:
-+            GException(_("v.build failed:\n%s" % msg))
-+
-+        environs = os.environ.copy()
-+        environs["GRASS_REGION"] = grass_region["GRASS_REGION"]
-+        environs['GRASS_VECTOR_TEMPORARY'] = '1'
-+
-+        ret, text, msg = RunCommand("v.to.rast",
-+                                    input = self.vectMap,
-+                                    use = "cat",
-+                                    layer = str(layer),
-+                                    cat = str(cat),
-+                                    output = out_rast,
-+                                    getErrorMsg = True,
-+                                    read = True,
-+                                    overwrite = True,
-+                                    env = environs)
-+
-+        if ret != 0:
-+            GException(_("v.to.rast failed:\n%s" % msg))
-+
-+    def _create_grass_region_env(self, bbox):
-+
-+        region = self.an_data.GetRegion()
-+        new_region = {}
-+
-+        if bbox["maxy"] <= region["s"]:
-+            return 0
-+        elif bbox["maxy"] >= region["n"]:
-+            new_region["n"] = bbox["maxy"]
-+        else:
-+            new_region["n"] = ceil((bbox["maxy"] - region["s"]) / region["nsres"]) * region["nsres"] + region["s"]
-+
-+        if bbox["miny"] >= region["n"]:
-+            return 0
-+        elif bbox["miny"] <= region["s"]:
-+            new_region["s"] = bbox["miny"]
-+        else:
-+            new_region["s"] = floor((bbox["miny"] - region["s"]) / region["nsres"]) * region["nsres"] + region["s"]
-+
-+        if bbox["maxx"] <= region["w"]:
-+            return 0
-+        elif bbox["maxx"] >= region["e"]:
-+            new_region["e"] = bbox["maxx"]
-+        else:
-+            new_region["e"] = ceil((bbox["maxx"] - region["w"]) / region["ewres"]) * region["ewres"] + region["w"]
-+
-+        if bbox["minx"] >= region["e"]:
-+            return 0
-+        elif bbox["minx"] <= region["w"]:
-+            new_region["w"] = bbox["minx"]
-+        else:
-+            new_region["w"] = floor((bbox["minx"] - region["w"]) / region["ewres"]) * region["ewres"] + region["w"]
-+
-+        #TODO check regions resolutin
-+        new_region["nsres"] = region["nsres"]
-+        new_region["ewres"] = region["ewres"]
-+
-+        return {"GRASS_REGION" :  grass.region_env(**new_region)}
-+
-+class AnalyzedData:
-+
-+    def __init__(self):
-+        
-+        self.bands = []
-+        self.bands_info = {}
-+
-+        self.region = None
-+
-+    def GetRegion(self):
-+        return self.region
-+
-+    def Create(self, bands):
-+
-+        self.bands = bands
-+        self.region = None
-+
-+        ret, region, msg = RunCommand("g.region",
-+                                      flags = "gp",
-+                                      getErrorMsg = True,
-+                                      read = True)
-+
-+        if  ret != 0:
-+            raise GException("g.region failed:\n%s" % msg)
-+
-+
-+        self.bands_info = {}
-+        for b in bands:
-+            self.bands_info[b] = self._getRasterInfo(b)
-+            if self.bands_info[b]["datatype"] != "CELL":
-+                raise GException(_("Raster <%s> is not <CELL> type.") % (b))
-+            #TODO size of raster check
-+
-+        self.region = self._parseRegion(region)
-+
-+    def _getRasterInfo(self, rast):
-+        """
-+        """
-+        ret, out, msg = RunCommand("r.info",
-+                                    map = rast,
-+                                    flags = "rg",
-+                                    getErrorMsg = True,
-+                                    read = True)
-+
-+        if  ret != 0:
-+            raise GException("r.info failed:\n%s" % msg)
-+
-+        out = out.split("\n")
-+        raster_info = {} 
-+
-+        for b in out:
-+            if not b.strip():
-+                continue
-+            k, v = b.split("=")
-+            if k == "datatype":
-+                pass
-+            elif k in ['rows', 'cols', 'cells', 'min', 'max']:
-+                v = int(v)
-+            else:
-+                v = float(v)
-+
-+            raster_info[k] = v
-+
-+        raster_info['range'] = raster_info['max'] - raster_info['min'] + 1
-+        return raster_info
-+
-+    def GetBands(self):
-+        return self.bands
-+
-+    def GetBandInfo(self, band_id):
-+        band = self.bands[band_id]
-+        return self.bands_info[band]
-+
-+    def _parseRegion(self, region_str):
-+
-+        region = {}
-+        region_str = region_str.splitlines()
-+
-+        for param in region_str:
-+            k, v = param.split("=")
-+            if k in ["rows", "cols", "cells"]:
-+                v = int(v)
-+            else:
-+                v = float(v)
-+            region[k] = v
-+
-+        return region
-+
-+class ScattPlotsCondsData:
-+
-+    def __init__(self, an_data):
-+
-+        self.an_data = an_data
-+
-+        #TODO
-+        self.max_n_cats = 10
-+    
-+        self.dtype = 'uint8'
-+        self.type = 1;
-+        self.CleanUp()
-+
-+    def CleanUp(self):
-+    
-+        self.cats = {}
-+
-+        self.n_scatts = -1
-+        self.n_bands = -1
-+
-+        for cat_id in self.cats.keys():
-+            self.DeleteCategory(cat_id)
-+
-+    def Create(self, n_bands):
-+
-+        self.CleanUp()
-+
-+        self.n_scatts =  (n_bands - 1) * n_bands / 2;
-+        self.n_bands = n_bands
-+
-+        self.AddCategory(cat_id = 0)
-+
-+    def AddCategory(self, cat_id):
-+
-+        if cat_id not in self.cats.keys():
-+            self.cats[cat_id] = {}
-+            return cat_id
-+        return -1
-+
-+    def DeleteCategory(self, cat_id):
-+
-+        if cat_id not in self.cats.keys():
-+            return False
-+
-+        for scatt in self.cats[cat_id].itervalues():
-+            del scatt['np_vals']
-+
-+        del self.cats[cat_id]
-+
-+        return True
-+
-+    def GetCategories(self):
-+        return self.cats.keys()
-+
-+    def GetCatScatts(self, cat_id):
-+
-+        if not self.cats.has_key(cat_id):
-+            return False
-+
-+        return self.cats[cat_id].keys()
-+
-+
-+    def AddScattPlot(self, cat_id, scatt_id):
-+
-+        if not self.cats.has_key(cat_id):
-+            return -1
-+
-+        if self.cats[cat_id].has_key(scatt_id):
-+            return 0
-+
-+        b_i = self.GetBandsInfo(scatt_id)
-+
-+        shape = (b_i['b2']['max'] - b_i['b2']['min'] + 1, b_i['b1']['max'] - b_i['b1']['min'] + 1)
-+
-+        np_vals = np.memmap(grass.tempfile(), dtype=self.dtype, mode='w+', shape = shape)
-+        np_vals.flush()
-+
-+        self.cats[cat_id][scatt_id] = {
-+                                        'np_vals' : np_vals,
-+                                      }
-+
-+        return 1
-+
-+    def GetBandsInfo(self, scatt_id):
-+        b1, b2 = idScattToidBands(scatt_id, len(self.an_data.GetBands()))
-+
-+        b1_info = self.an_data.GetBandInfo(b1)
-+        b2_info = self.an_data.GetBandInfo(b2)
-+
-+        bands_info = {'b1' : b1_info,
-+                      'b2' : b2_info}
-+
-+        return bands_info
-+
-+    def DeleScattPlot(self, cat_id, scatt_id):
-+
-+        if not self.cats.has_key(cat_id):
-+            return False
-+
-+        if not self.cats[cat_id].has_key(scatt_id):
-+            return False
-+
-+        del self.cats[cat_id][scatt_id]
-+        return True
-+
-+    def GetValuesArr(self, cat_id, scatt_id):
-+
-+        if not self.cats.has_key(cat_id):
-+            return None
-+
-+        if not self.cats[cat_id].has_key(scatt_id):
-+            return None
-+
-+        return self.cats[cat_id][scatt_id]['np_vals']
-+
-+    def GetData(self, requested_dt):
-+        
-+        cats = {}
-+        for cat_id, scatt_ids in requested_dt.iteritems():
-+            if not cats.has_key(cat_id):
-+                cats[cat_id] = {}
-+            for scatt_id in scatt_ids:
-+                # if key is missing condition is always True (full scatter plor is computed)
-+                if self.cats[cat_id].has_key(scatt_id):
-+                    cats[cat_id][scatt_id] = {'np_vals' : self.cats[cat_id][scatt_id]['np_vals'],
-+                                              'bands_info' : self.GetBandsInfo(scatt_id)}
-+                        
-+        return cats
-+
-+    def SetData(self, cats):
-+        
-+        for cat_id, scatt_ids in cats.iteritems():            
-+            for scatt_id in scatt_ids:
-+                # if key is missing condition is always True (full scatter plor is computed)
-+                if self.cats[cat_id].has_key(scatt_id):
-+                    self.cats[cat_id][scatt_id]['np_vals'] = cats[cat_id][scatt_id]['np_vals']
-+                   
-+class ScattPlotsData(ScattPlotsCondsData):
-+
-+    def __init__(self, an_data):
-+
-+        self.cats_rasts = {}
-+        self.cats_rasts_conds = {}    
-+        self.scatts_ids = []    
-+
-+        ScattPlotsCondsData.__init__(self, an_data)
-+
-+        self.dtype = 'uint32'
-+
-+        #TODO
-+        self.type = 0
-+
-+    def AddCategory(self, cat_id):
-+        cat_id = ScattPlotsCondsData.AddCategory(self, cat_id)
-+        if cat_id < 0:
-+            return cat_id
-+
-+        for scatt_id in self.scatts_ids:
-+            ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
-+
-+        if cat_id == 0:
-+            self.cats_rasts_conds[cat_id] = None
-+            self.cats_rasts[cat_id] = None
-+        else:
-+            self.cats_rasts_conds[cat_id] = grass.tempfile()
-+            self.cats_rasts[cat_id] = "temp_cat_rast_%d" % cat_id
-+            region = self.an_data.GetRegion()
-+            CreateCatRast(region, self.cats_rasts_conds[cat_id])
-+
-+        return cat_id
-+
-+    def DeleteCategory(self, cat_id):
-+
-+        ScattPlotsCondsData.DeleteCategory(self, cat_id)
-+
-+        grass.try_remove(self.cats_rasts_conds[cat_id])
-+        del self.cats_rasts_conds[cat_id]
-+
-+        grass.try_remove(self.cats_rasts[cat_id])
-+        del self.cats_rasts[cat_id]
-+
-+        return True
-+
-+    def AddScattPlot(self, scatt_id):
-+        
-+        if scatt_id in self.scatts_ids:
-+            return False
-+
-+        self.scatts_ids.append(scatt_id)
-+        for cat_id in self.cats.iterkeys():
-+                ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
-+                self.cats[cat_id][scatt_id]['ellipse'] = None
-+
-+        return True
-+
-+    def DeleteScatterPlot(self, scatt_id):
-+        
-+        if scatt_id not in self.scatts_ids:
-+            return False
-+
-+        self.scatts_ids.remove(scatt_id)
-+
-+        for cat_id in self.cats.iterkeys():
-+                ScattPlotsCondsData.DeleteScattPlot(self, cat_id, scatt_id)
-+
-+        return True
-+
-+    def GetScatt(self, scatt_id, cats_ids = None):
-+        if scatt_id not in self.scatts_ids:
-+            return False
-+
-+        scatts = {}
-+        for cat_id in self.cats.iterkeys():
-+            if cats_ids and cat_id not in cats_ids:
-+                continue
-+            scatts[cat_id] = {'np_vals' : self.cats[cat_id][scatt_id]['np_vals'],
-+                              'bands_info' : self.GetBandsInfo(scatt_id)}
-+        return scatts
-+
-+    def GetEllipses(self, scatt_id):
-+        if scatt_id not in self.scatts_ids:
-+            return False
-+
-+        scatts = {}
-+        for cat_id in self.cats.iterkeys():
-+            if cat_id == 0:
-+                continue
-+            scatts[cat_id] = self._getEllipse(cat_id, scatt_id)
-+
-+        return scatts
-+
-+    def _getEllipse(self, cat_id, scatt_id):
-+        # Joe Kington
-+        # http://stackoverflow.com/questions/12301071/multidimensional-confidence-intervals
-+
-+        nstd = 2
-+        data = np.copy(self.cats[cat_id][scatt_id]['np_vals'])
-+
-+        sel_pts = np.where(data > 0)
-+
-+        x = sel_pts[1]
-+        y = sel_pts[0]
-+
-+        flatten_data = data.reshape([-1])
-+        flatten_sel_pts = np.nonzero(flatten_data)
-+        weights = flatten_data[flatten_sel_pts]
-+        if len(weights) == 0:
-+            return None
-+
-+        x_avg = np.average(x, weights=weights)
-+        y_avg = np.average(y, weights=weights)
-+        pos = np.array([x_avg, y_avg])
-+
-+        x_diff = (x - x_avg)
-+        y_diff = (y - y_avg)
-+        
-+        x_diff = (x - x_avg) 
-+        y_diff = (y - y_avg) 
-+
-+        diffs = x_diff * y_diff.T
-+        cov = np.dot(diffs, weights) / (np.sum(weights) - 1)
-+
-+        diffs = x_diff * x_diff.T
-+        var_x = np.dot(diffs, weights) /  (np.sum(weights) - 1)
-+        
-+        diffs = y_diff * y_diff.T
-+        var_y = np.dot(diffs, weights) /  (np.sum(weights) - 1)
-+
-+        cov = np.array([[var_x, cov],[cov, var_y]])
-+
-+        def eigsorted(cov):
-+            vals, vecs = np.linalg.eigh(cov)
-+            order = vals.argsort()[::-1]
-+            return vals[order], vecs[:,order]
-+
-+        vals, vecs = eigsorted(cov)
-+        theta = np.degrees(np.arctan2(*vecs[:,0][::-1]))
-+
-+        # Width and height are "full" widths, not radius
-+        width, height = 2 * nstd * np.sqrt(vals)
-+
-+        ellipse = {'pos' : pos, 
-+                   'width' : width,
-+                   'height' : height,
-+                   'theta' : theta}
-+
-+        del data
-+        del flatten_data
-+        del flatten_sel_pts
-+        del weights
-+        del sel_pts
-+        return ellipse
-+
-+    def CleanUp(self):
-+
-+        ScattPlotsCondsData.CleanUp(self)        
-+        for tmp in self.cats_rasts_conds:
-+            grass.try_remove(tmp) 
-+        for tmp in self.cats_rasts:
-+            grass.try_remove(tmp) 
-+
-+        self.cats_rasts = {}
-+        self.cats_rasts_conds = {}
-+
-+
-+    def GetCatRast(self, cat_id):
-+        return self.cats_rasts[cat_id]
-+
-+    def GetCatRastCond(self, cat_id):
-+        return self.cats_rasts_conds[cat_id]
-+
-+    def GetCatsRastsConds(self):
-+        max_cat_id = max(self.cats_rasts_conds.keys())
-+
-+        cats_rasts_conds = [''] * (max_cat_id + 1)
-+        for i_cat_id, i_rast in self.cats_rasts_conds.iteritems():
-+            cats_rasts_conds[i_cat_id] = i_rast
-+
-+        return cats_rasts_conds
-+
-+    def GetCatsRasts(self):
-+        max_cat_id = max(self.cats_rasts.keys())
-+
-+        cats_rasts = [''] * (max_cat_id + 1)
-+        for i_cat_id, i_rast in self.cats_rasts.iteritems():
-+            cats_rasts[i_cat_id] = i_rast
-+
-+        return cats_rasts
-+
-+
-+def RasterizePolygon(pol, height, width):
-+
-+    # Joe Kington
-+    # http://stackoverflow.com/questions/3654289/scipy-create-2d-polygon-mask
-+
-+    #poly_verts = [(1,1), (1,4), (4,4),(4,1), (1,1)]
-+
-+    nx = width + 1
-+    ny = height + 1
-+
-+    x, y = np.meshgrid(np.arange(nx), np.arange(ny))
-+    x, y = x.flatten(), y.flatten()
-+
-+    points = np.vstack((x,y)).T
-+
-+    grid = points_inside_poly(points, pol)
-+    grid = grid.reshape((ny,nx))
-+    
-+    raster = np.zeros((height, width), dtype=np.uint8)#TODO bool
-+
-+    #TODO this part is very inefficient, replace it with better solution
-+    for (y, x), value in np.ndenumerate(grid):
-+
-+        if x >= width - 1: continue 
-+        if y >= height - 1: continue
-+
-+        if grid[y, x]:
-+            raster[y, x] = 1
-+            raster[y + 1, x] = 1
-+            raster[y, x + 1] = 1
-+            raster[y + 1, x + 1] = 1
-+
-+    return raster
-+
-+#TODO move to utils?
-+def idScattToidBands(scatt_id, n_bands):
-+ 
-+    n_b1 = n_bands - 1
-+
-+    band_1 = (int) ((2 * n_b1 + 1 - sqrt(((2 * n_b1 + 1) * (2 * n_b1 + 1) - 8 * scatt_id))) / 2)
-+
-+    band_2 = scatt_id - (band_1 * (2 * n_b1 + 1) - band_1 * band_1) / 2 + band_1 + 1
-+
-+    return band_1, band_2
-+
-+def idBandsToidScatt(band_1_id, band_2_id, n_bands):
-+
-+    if band_2_id <  band_1_id:
-+        tmp = band_1
-+        band_1_id = band_2_id
-+        band_2_id = tmp
-+
-+    n_b1 = n_bands - 1
-+
-+    scatt_id = (band_1_id * (2 * n_b1 + 1) - band_1_id * band_1_id) / 2 + band_2_id - band_1_id - 1
-+
-+    return scatt_id
-+
-Index: gui/wxpython/Makefile
-===================================================================
---- gui/wxpython/Makefile	(revision 57529)
-+++ 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/vdigit/wxdigit.py
 ===================================================================
---- gui/wxpython/vdigit/wxdigit.py	(revision 57529)
+--- gui/wxpython/vdigit/wxdigit.py	(revision 57546)
 +++ gui/wxpython/vdigit/wxdigit.py	(working copy)
 @@ -17,7 +17,7 @@
  (and NumPy would be an excellent candidate for acceleration via
@@ -3875,7 +5390,7 @@
      def GetLineCats(self, line):
 Index: gui/wxpython/vdigit/toolbars.py
 ===================================================================
---- gui/wxpython/vdigit/toolbars.py	(revision 57529)
+--- gui/wxpython/vdigit/toolbars.py	(revision 57546)
 +++ gui/wxpython/vdigit/toolbars.py	(working copy)
 @@ -17,6 +17,7 @@
  import wx
@@ -3902,1541 +5417,27 @@
          return True
  
      def StopEditing(self):
-Index: gui/wxpython/iclass/dialogs.py
+Index: gui/wxpython/Makefile
 ===================================================================
---- gui/wxpython/iclass/dialogs.py	(revision 57529)
-+++ gui/wxpython/iclass/dialogs.py	(working copy)
-@@ -333,13 +333,19 @@
-         toolbar.SetCategories(catNames = catNames, catIdx = cats)
-         if name in catNames:
-             toolbar.choice.SetStringSelection(name)
-+            cat = toolbar.GetSelectedCategoryIdx()
-         elif catNames:
-             toolbar.choice.SetSelection(0)
--            
-+            cat = toolbar.GetSelectedCategoryIdx()
-+        else:
-+            cat = None
-+
-         if toolbar.choice.IsEmpty():
-             toolbar.EnableControls(False)
-         else:
-             toolbar.EnableControls(True)
-+
-+        self.mapWindow.CategoryChanged(cat)
-         # don't forget to update maps, histo, ...
-         
-     def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
-Index: gui/wxpython/iclass/toolbars.py
-===================================================================
---- gui/wxpython/iclass/toolbars.py	(revision 57529)
-+++ gui/wxpython/iclass/toolbars.py	(working copy)
-@@ -46,9 +46,7 @@
-         'importAreas' : MetaIcon(img = 'layer-import',
-                             label = _('Import training areas from vector map')),
-         'addRgb' : MetaIcon(img = 'layer-rgb-add',
--                            label = _('Add RGB map layer')),
--        'scatt_plot'    : MetaIcon(img = 'layer-raster-analyze',
--                                   label = _('Open Scatter Plot Tool (EXPERIMENTAL GSoC 2013)')),
-+                            label = _('Add RGB map layer'))
-         }
-         
- class IClassMapToolbar(BaseToolbar):
-@@ -117,10 +115,7 @@
-                                      ("zoomBack", icons["zoomBack"],
-                                       self.parent.OnZoomBack),
-                                      ("zoomToMap", icons["zoomExtent"],
--                                      self.parent.OnZoomToMap),
--                                     (None, ),
--                                     ("scatt_plot", iClassIcons["scatt_plot"],
--                                      self.parent.OnScatterplot)
-+                                      self.parent.OnZoomToMap)
-                                     ))
- class IClassToolbar(BaseToolbar):
-     """!IClass toolbar
-@@ -156,7 +151,7 @@
-         """!Toolbar data"""
-         icons = iClassIcons
-         return self._getToolbarData((("selectGroup", icons['selectGroup'],
--                                      self.parent.OnAddBands),
-+                                      lambda event : self.parent.AddBands()),
-                                       (None, ),
-                                       ("classManager", icons['classManager'],
-                                       self.parent.OnCategoryManager),
-Index: gui/wxpython/iclass/frame.py
-===================================================================
---- gui/wxpython/iclass/frame.py	(revision 57529)
-+++ gui/wxpython/iclass/frame.py	(working copy)
-@@ -64,6 +64,8 @@
-                                IClassExportAreasDialog, IClassMapDialog
- from iclass.plots       import PlotPanel
+--- gui/wxpython/Makefile	(revision 57546)
++++ 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
  
-+from grass.pydispatch.signal import Signal
-+
- class IClassMapFrame(DoubleMapFrame):
-     """! wxIClass main frame
-     
-@@ -114,6 +116,10 @@
-             lambda:
-             self.statusbarManager.statusbarItems['coordinates'].SetAdditionalInfo(None))
-         self.SetSize(size)
-+
-+        self.groupSet = Signal("IClassMapFrame.groupSet")
-+        self.categoryChanged = Signal('IClassMapFrame.categoryChanged')
-+
-         #
-         # Add toolbars
-         #
-@@ -177,7 +183,7 @@
-         self.dialogs['category']   = None
-         
-         # PyPlot init
--        self.plotPanel = PlotPanel(self, stats_data = self.stats_data)
-+        self.plotPanel = PlotPanel(self, giface = self._giface, stats_data = self.stats_data)
-                                    
-         self._addPanes()
-         self._mgr.Update()
-@@ -237,7 +243,7 @@
-             return False
-         
-         return vectorName
--        
-+    
-     def RemoveTempVector(self):
-         """!Removes temporary vector map with training areas"""
-         ret = RunCommand(prog = 'g.remove',
-@@ -477,7 +483,7 @@
-         
-         self.Render(self.GetFirstWindow())
-         
--    def OnAddBands(self, event):
-+    def AddBands(self):
-         """!Add imagery group"""
-         dlg = IClassGroupDialog(self, group = self.group)
-         if dlg.ShowModal() == wx.ID_OK:
-@@ -488,7 +494,8 @@
-         """!Set imagery group"""
-         group = grass.find_file(name = name, element = 'group')
-         if group['name']:
--            self.group = group['name']
-+           self.group = group['name']
-+           self.groupSet.emit(group = group['name'])
-         else:
-             GError(_("Group <%s> not found") % name, parent = self)
-     
-@@ -768,17 +775,20 @@
-         
-         Updates number of stddev, histograms, layer in preview display. 
-         """
--        stat = self.stats_data.GetStatistics(currentCat)
--        nstd = stat.nstd
--        self.toolbars['iClass'].UpdateStddev(nstd)
--        
--        self.plotPanel.UpdateCategory(currentCat)
--        self.plotPanel.OnPlotTypeSelected(None)
-+        if currentCat:
-+          stat = self.stats_data.GetStatistics(currentCat)
-+          nstd = stat.nstd
-+          self.toolbars['iClass'].UpdateStddev(nstd)
-+          
-+          self.plotPanel.UpdateCategory(currentCat)
-+          self.plotPanel.OnPlotTypeSelected(None)
-                                    
--        name = stat.rasterName
--        name = self.previewMapManager.GetAlias(name)
--        if name:
--            self.previewMapManager.SelectLayer(name)
-+          name = stat.rasterName
-+          name = self.previewMapManager.GetAlias(name)
-+          if name:
-+              self.previewMapManager.SelectLayer(name)
-+
-+        self.categoryChanged.emit(cat = currentCat)
-         
-     def DeleteAreas(self, cats):
-         """!Removes all training areas of given categories
-@@ -1105,27 +1115,6 @@
-         self.GetFirstWindow().SetModePointer()
-         self.GetSecondWindow().SetModePointer()
+ DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES)) \
+@@ -21,8 +21,9 @@
  
--    def OnScatterplot(self, event):
--        """!Init interactive scatterplot tools
--        """
--        if self.dialogs['scatt_plot']:
--            self.dialogs['scatt_plot'].Raise()
--            return
--
--        try:
--          from scatt_plot.dialogs import ScattPlotMainDialog
--        except:
--          GError(parent  = self, message = _("The Scatter Plot Tool is not installed."))
--          return
--
--        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface, iclass_mapwin = self.GetFirstWindow())
--
--        scatt_mgr = self.dialogs['scatt_plot'].GetScattMgr()
--        scatt_mgr.DigitDataChanged(self.toolbars['vdigit'].mapLayer.GetName(), self.GetFirstWindow().GetDigit())
--
--        self.dialogs['scatt_plot'].CenterOnScreen()
--        self.dialogs['scatt_plot'].Show()
--
- class MapManager:
-     """! Class for managing map renderer.
-     
-Index: gui/wxpython/iclass/plots.py
-===================================================================
---- gui/wxpython/iclass/plots.py	(revision 57529)
-+++ gui/wxpython/iclass/plots.py	(working copy)
-@@ -28,7 +28,7 @@
-     for each band and for one category. Coincidence plots show min max range
-     of classes for each band.
-     """
--    def __init__(self, parent, stats_data):
-+    def __init__(self, parent, giface, stats_data):
-         scrolled.ScrolledPanel.__init__(self, parent)
-         
-         self.SetupScrolling(scroll_x = False, scroll_y = True)
-@@ -38,26 +38,64 @@
-         self.stats_data = stats_data
-         self.currentCat = None
-         
-+        self._giface = giface
+ 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)
+ 
 +
-         self.mainSizer = wx.BoxSizer(wx.VERTICAL)
--        
-+
-         self._createControlPanel()
--        
-+        self._createPlotPanel()
-+        self._createScatterPlotPanel()
-+
-         self.SetSizer(self.mainSizer)
-         self.mainSizer.Fit(self)
-         self.Layout()
--        
-+
-+    def _createPlotPanel(self):
-+
-+        self.canvasPanel = wx.Panel(parent=self)
-+        self.mainSizer.Add(item = self.canvasPanel, proportion = 1, flag = wx.EXPAND, border = 0)
-+        self.canvasSizer = wx.BoxSizer(wx.VERTICAL)
-+        self.canvasPanel.SetSizer(self.canvasSizer)
-+
-     def _createControlPanel(self):
-         self.plotSwitch = wx.Choice(self, id = wx.ID_ANY,
-                                      choices = [_("Histograms"),
--                                                _("Coincident plots")])
-+                                                _("Coincident plots"),
-+                                                _("Scatter plots")])
-         self.mainSizer.Add(self.plotSwitch, proportion = 0, flag = wx.EXPAND|wx.ALL, border = 5)
-         self.plotSwitch.Bind(wx.EVT_CHOICE, self.OnPlotTypeSelected)
--        
-+    
-+    def _createScatterPlotPanel(self):
-+        """!Init interactive scatterplot tools
-+        """
-+        try:
-+            from scatt_plot.frame import IClassScatterPlotsPanel
-+            self.scatt_plot_panel = IClassScatterPlotsPanel(parent=self, giface=self._giface, iclass_mapwin = self.parent.GetFirstWindow())
-+            self.mainSizer.Add(self.scatt_plot_panel, proportion = 1, flag = wx.EXPAND, border = 0)
-+            self.scatt_plot_panel.Hide()
-+        except ImportError as e:#TODO
-+            print "ahoj"
-+            print e
-+            self.scatt_plot_panel = None
-+
-     def OnPlotTypeSelected(self, event):
-         """!Plot type selected"""
-+
-+        if self.plotSwitch.GetSelection() in [0, 1]:
-+            self.SetupScrolling(scroll_x = False, scroll_y = True)
-+            self.scatt_plot_panel.Hide()
-+            self.canvasPanel.Show()
-+            self.Layout()
-+
-+        elif self.plotSwitch.GetSelection() == 2:
-+            self.SetupScrolling(scroll_x = False, scroll_y = False)
-+            self.scatt_plot_panel.Show()
-+            self.canvasPanel.Hide()
-+            self.Layout()
-+
-         if self.currentCat is None:
-             return
--        
-+
-         if self.plotSwitch.GetSelection() == 0:
-             stat = self.stats_data.GetStatistics(self.currentCat)
-             if not stat.IsReady():
-@@ -66,7 +104,10 @@
-             self.DrawHistograms(stat)
-         else:
-             self.DrawCoincidencePlots()
--            
-+
-+        self.Layout()
-+
-+
-     def StddevChanged(self):
-         """!Standard deviation multiplier changed, redraw histograms"""
-         if self.plotSwitch.GetSelection() == 0:
-@@ -89,7 +130,7 @@
-             panel.Destroy()
-             
-         self.canvasList = []
--            
-+
-     def ClearPlots(self):
-         """!Clears plot canvases"""
-         for bandIdx in range(len(self.bandList)):
-@@ -104,15 +145,15 @@
-     def CreatePlotCanvases(self):
-         """!Create plot canvases according to the number of bands"""
-         for band in self.bandList:
--            canvas = plot.PlotCanvas(self)
-+            canvas = plot.PlotCanvas(self.canvasPanel)
-             canvas.SetMinSize((-1, 140))
-             canvas.SetFontSizeTitle(10)
-             canvas.SetFontSizeAxis(8)
-             self.canvasList.append(canvas)
-             
--            self.mainSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
--
--        self.SetVirtualSize(self.GetBestVirtualSize()) 
-+            self.canvasSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
-+        
-+        self.SetVirtualSize(self.GetBestVirtualSize())
-         self.Layout()
-         
-     def UpdatePlots(self, group, currentCat, stats_data):
-@@ -138,7 +179,7 @@
-         
-     def UpdateCategory(self, cat):
-         self.currentCat = cat
--        
-+    
-     def DrawCoincidencePlots(self):
-         """!Draw coincidence plots"""
-         for bandIdx in range(len(self.bandList)):
-Index: gui/wxpython/mapdisp/toolbars.py
-===================================================================
---- gui/wxpython/mapdisp/toolbars.py	(revision 57529)
-+++ 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 57529)
-+++ 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']
+ DSTDIRS := $(patsubst %,$(ETCDIR)/%,icons scripts xml)
  
-+    def OnScatterplot2(self, event):
-+        """!Init interactive scatterplot tools
-+        """
-+        if self.dialogs['scatt_plot']:
-+            self.dialogs['scatt_plot'].Raise()
-+            return
-+
-+        from scatt_plot.dialogs import ScattPlotMainDialog
-+        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface)
-+        
-+        self.dialogs['scatt_plot'].CenterOnScreen()
-+        self.dialogs['scatt_plot'].Show()
-+
-     def OnVNet(self, event):
-         """!Dialog for v.net* modules 
-         """
-Index: lib/imagery/scatt.c
-===================================================================
---- lib/imagery/scatt.c	(revision 0)
-+++ lib/imagery/scatt.c	(working copy)
-@@ -0,0 +1,746 @@
-+/*!
-+   \file lib/imagery/scatt.c
-+
-+   \brief Imagery library - functions for wx Scatter Plot Tool.
-+
-+   Low level functions used by wx Scatter Plot Tool.
-+
-+   Copyright (C) 2013 by the GRASS Development Team
-+
-+   This program is free software under the GNU General Public License
-+   (>=v2).  Read the file COPYING that comes with GRASS for details.
-+
-+   \author Stepan Turek <stepan.turek at seznam.cz> (Mentor: Martin Landa)
-+ */
-+
-+#include <grass/raster.h>
-+#include <grass/imagery.h>
-+#include <grass/gis.h>
-+#include <grass/glocale.h>
-+
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <math.h>
-+#include <string.h>
-+
-+
-+struct rast_row
-+{
-+    CELL * row;
-+    char * null_row;
-+    struct Range rast_range; /*Range of whole raster.*/
-+};
-+
-+/*!
-+   \brief Create pgm header.
-+
-+   Scatter plot internally generates pgm files. These pgms have header in format created by this function.
-+    
-+   \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;
-+
-+    unsigned char * row_data;
-+
-+    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 
-+*/
-+static int get_rows_and_cols_bounds(struct Cell_head * A,  struct Cell_head * B, struct Cell_head * A_bounds,  struct Cell_head * B_bounds)
-+{
-+    float ns_res, ew_res;
-+
-+    struct Cell_head intersec;
-+
-+    /* 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();
-+    
-+    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);
-+
-+        for(i_col = 0; i_col < ncols; i_col++) {
-+            patch_col = patch_bounds.west + i_col;
-+
-+            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
-+*/
-+static inline void update_cat_scatt_plts(struct rast_row * bands_rows, unsigned short * belongs_pix, struct scScatts * scatts)
-+{
-+    int band_axis_1, band_axis_2, i_scatt, array_idx, cat_idx, i_chunk_rows_pix, max_arr_idx;
-+
-+    CELL * b_1_row;
-+    CELL * b_2_row;
-+    char * b_1_null_row,* b_2_null_row;
-+    struct rast_row b_1_rast_row, b_2_rast_row;
-+
-+    struct Range b_1_range, b_2_range;
-+    int b_1_range_size;
-+
-+    int row_size = Rast_window_cols();
-+
-+    int * scatts_bands = scatts->scatts_bands;
-+
-+    for(i_scatt = 0; i_scatt < scatts->n_a_scatts; i_scatt++)
-+    {   
-+        b_1_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;    
-+}
-\ No newline at end of file
-Index: lib/imagery/scatt_sccats.c
-===================================================================
---- lib/imagery/scatt_sccats.c	(revision 0)
-+++ lib/imagery/scatt_sccats.c	(working copy)
-@@ -0,0 +1,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 57529)
-+++ 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)
+ default: $(DSTFILES)



More information about the grass-commit mailing list