[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