GRASS GIS 8 Programmer's Manual  8.5.0dev(2025)-565e82de51
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
iscatt_core.c
Go to the documentation of this file.
1 /*!
2  \file lib/imagery/iscatt_core.c
3 
4  \brief Imagery library - wx.iscatt (wx Interactive Scatter Plot Tool)
5  backend.
6 
7  Copyright (C) 2013 by the GRASS Development Team
8 
9  This program is free software under the GNU General Public License
10  (>=v2). Read the file COPYING that comes with GRASS for details.
11 
12  \author Stepan Turek <stepan.turek@seznam.cz> (GSoC 2013, Mentor: Martin
13  Landa)
14  */
15 
16 #include <stdio.h>
17 #include <string.h>
18 #include <math.h>
19 
20 #include <grass/gis.h>
21 #include <grass/vector.h>
22 #include <grass/raster.h>
23 #include <grass/imagery.h>
24 #include <grass/glocale.h>
25 
26 #include "iclass_local_proto.h"
27 
28 struct rast_row {
29  CELL *row;
30  char *null_row;
31  struct Range rast_range; /*Range of whole raster. */
32 };
33 
34 /*!
35  \brief Create pgm header.
36 
37  Scatter plot internally generates pgm files.
38  These pgms have header in format created by this function.
39 
40  \param region region to be pgm header generated for
41  \param [out] header header of pgm file
42  */
43 static int get_cat_rast_header(struct Cell_head *region, char *header)
44 {
45  return sprintf(header, "P5\n%d\n%d\n1\n", region->cols, region->rows);
46 }
47 
48 /*!
49  \brief Create category raster conditions file.
50  The file is used for holding selected areas from mapwindow.
51  The reason why the standard GRASS raster is not used is that for every
52  modification (new area is selected) we would need to create whole new raster.
53  Instead of this scatter plot only modifies affected region in
54  the internal pgm file.
55 
56  \param cat_rast_region region to be file generated for
57  \param[out] cat_rast path where the pgm raster file will be generated
58  */
59 int I_create_cat_rast(struct Cell_head *cat_rast_region, const char *cat_rast)
60 {
61  FILE *f_cat_rast;
62  char cat_rast_header[1024]; /* TODO magic number */
63  int i_row, i_col;
64  int head_nchars;
65 
66  unsigned char *row_data;
67 
68  f_cat_rast = fopen(cat_rast, "wb");
69  if (!f_cat_rast) {
70  G_warning("Unable to create category raster condition file <%s>.",
71  cat_rast);
72  return -1;
73  }
74 
75  head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
76 
77  fwrite(cat_rast_header, sizeof(char), head_nchars / sizeof(char),
78  f_cat_rast);
79  if (ferror(f_cat_rast)) {
80  fclose(f_cat_rast);
81  G_warning(_("Unable to write header into category raster condition "
82  "file <%s>."),
83  cat_rast);
84  return -1;
85  }
86 
87  row_data = (unsigned char *)G_malloc(cat_rast_region->cols *
88  sizeof(unsigned char));
89  for (i_col = 0; i_col < cat_rast_region->cols; i_col++)
90  row_data[i_col] = 0 & 255;
91 
92  for (i_row = 0; i_row < cat_rast_region->rows; i_row++) {
93  fwrite(row_data, sizeof(unsigned char),
94  (cat_rast_region->cols) / sizeof(unsigned char), f_cat_rast);
95  if (ferror(f_cat_rast)) {
96  fclose(f_cat_rast);
97  G_warning(
98  _("Unable to write into category raster condition file <%s>."),
99  cat_rast);
100  return -1;
101  }
102  }
103 
104  fclose(f_cat_rast);
105  return 0;
106 }
107 
108 /*!
109  \brief Find intersection region of two regions.
110 
111  \param A pointer to intersected region
112  \param B pointer to intersected region
113  \param [out] intersec pointer to intersection region of regions A B
114  (relevant params of the region are: south, north, east, west)
115 
116  \return 0 if interaction exists
117  \return -1 if regions does not intersect
118  */
119 static int regions_intersecion(struct Cell_head *A, struct Cell_head *B,
120  struct Cell_head *intersec)
121 {
122 
123  if (B->north < A->south)
124  return -1;
125  else if (B->north > A->north)
126  intersec->north = A->north;
127  else
128  intersec->north = B->north;
129 
130  if (B->south > A->north)
131  return -1;
132  else if (B->south < A->south)
133  intersec->south = A->south;
134  else
135  intersec->south = B->south;
136 
137  if (B->east < A->west)
138  return -1;
139  else if (B->east > A->east)
140  intersec->east = A->east;
141  else
142  intersec->east = B->east;
143 
144  if (B->west > A->east)
145  return -1;
146  else if (B->west < A->west)
147  intersec->west = A->west;
148  else
149  intersec->west = B->west;
150 
151  if (intersec->north == intersec->south)
152  return -1;
153 
154  if (intersec->east == intersec->west)
155  return -1;
156 
157  return 0;
158 }
159 
160 /*!
161  \brief Get rows and cols numbers, which defines intersection of the regions.
162 
163  \param A pointer to intersected region
164  \param B pointer to intersected region (A and B must have same resolution)
165  \param [out] A_bounds rows and cols numbers of A stored in
166  south, north, east, west, which defines intersection of A and B
167  \param [out] B_bounds rows and cols numbers of B stored in
168  south, north, east, west, which defines intersection of A and B
169 
170  \return 0 if interaction exists
171  \return -1 if regions do not intersect
172  \return -2 resolution of regions is not same
173  */
174 static int get_rows_and_cols_bounds(struct Cell_head *A, struct Cell_head *B,
175  struct Cell_head *A_bounds,
176  struct Cell_head *B_bounds)
177 {
178  float ns_res, ew_res;
179 
180  struct Cell_head intersec;
181 
182  /* TODO is it right check? */
183  if (fabs(A->ns_res - B->ns_res) > GRASS_EPSILON) {
184  G_warning("'get_rows_and_cols_bounds' ns_res does not fit, A->ns_res: "
185  "%f B->ns_res: %f",
186  A->ns_res, B->ns_res);
187  return -2;
188  }
189 
190  if (fabs(A->ew_res - B->ew_res) > GRASS_EPSILON) {
191  G_warning("'get_rows_and_cols_bounds' ew_res does not fit, A->ew_res: "
192  "%f B->ew_res: %f",
193  A->ew_res, B->ew_res);
194  return -2;
195  }
196 
197  ns_res = A->ns_res;
198  ew_res = A->ew_res;
199 
200  if (regions_intersecion(A, B, &intersec) == -1)
201  return -1;
202 
203  A_bounds->north = ceil((A->north - intersec.north - ns_res * 0.5) / ns_res);
204  A_bounds->south = ceil((A->north - intersec.south - ns_res * 0.5) / ns_res);
205 
206  A_bounds->east = ceil((intersec.east - A->west - ew_res * 0.5) / ew_res);
207  A_bounds->west = ceil((intersec.west - A->west - ew_res * 0.5) / ew_res);
208 
209  B_bounds->north = ceil((B->north - intersec.north - ns_res * 0.5) / ns_res);
210  B_bounds->south = ceil((B->north - intersec.south - ns_res * 0.5) / ns_res);
211 
212  B_bounds->east = ceil((intersec.east - B->west - ew_res * 0.5) / ew_res);
213  B_bounds->west = ceil((intersec.west - B->west - ew_res * 0.5) / ew_res);
214 
215  return 0;
216 }
217 
218 /*!
219  \brief Insert raster map patch into pgm file.
220  \see I_create_cat_rast
221 
222  Warning: calls Rast_set_window
223 
224  \param patch_rast name of raster map
225  \param cat_rast_region region of category raster file
226  \param cat_rast path to category raster file
227 
228  \return 0 on success
229  \return -1 on failure
230  */
231 int I_insert_patch_to_cat_rast(const char *patch_rast,
232  struct Cell_head *cat_rast_region,
233  const char *cat_rast)
234 {
235 
236  FILE *f_cat_rast;
237  struct Cell_head patch_region, patch_bounds, cat_rast_bounds;
238  char cat_rast_header[1024];
239  int i_row, i_col, ncols, nrows, patch_col;
240  int head_nchars, ret;
241  int fd_patch_rast, init_shift, step_shift;
242  unsigned char *patch_data;
243 
244  char *null_chunk_row;
245 
246  const char *mapset;
247 
248  f_cat_rast = fopen(cat_rast, "rb+");
249  if (!f_cat_rast) {
250  G_warning(_("Unable to open category raster conditions file <%s>."),
251  cat_rast);
252  return -1;
253  }
254 
255  head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
256  if ((mapset = G_find_raster((char *)patch_rast, "")) == NULL) {
257  fclose(f_cat_rast);
258  G_warning(_("Unable to find patch raster <%s>."), patch_rast);
259  return -1;
260  }
261 
262  Rast_get_cellhd(patch_rast, mapset, &patch_region);
263  Rast_set_window(&patch_region);
264 
265  if ((fd_patch_rast = Rast_open_old(patch_rast, mapset)) < 0) {
266  fclose(f_cat_rast);
267  return -1;
268  }
269 
270  ret = get_rows_and_cols_bounds(cat_rast_region, &patch_region,
271  &cat_rast_bounds, &patch_bounds);
272  if (ret == -2) {
273  G_warning(
274  _("Resolutions of patch <%s> and patched file <%s> are not same."),
275  patch_rast, cat_rast);
276 
277  Rast_close(fd_patch_rast);
278  fclose(f_cat_rast);
279 
280  return -1;
281  }
282  else if (ret == -1) {
283 
284  Rast_close(fd_patch_rast);
285  fclose(f_cat_rast);
286 
287  return 0;
288  }
289 
290  ncols = cat_rast_bounds.east - cat_rast_bounds.west;
291  nrows = cat_rast_bounds.south - cat_rast_bounds.north;
292 
293  patch_data = (unsigned char *)G_malloc(ncols * sizeof(unsigned char));
294 
295  init_shift = head_nchars + cat_rast_region->cols * cat_rast_bounds.north +
296  cat_rast_bounds.west;
297 
298  if (fseek(f_cat_rast, init_shift, SEEK_SET) != 0) {
299  G_warning(
300  _("Corrupted category raster conditions file <%s> (fseek failed)"),
301  cat_rast);
302 
303  Rast_close(fd_patch_rast);
304  fclose(f_cat_rast);
305 
306  return -1;
307  }
308 
309  step_shift = cat_rast_region->cols - ncols;
310 
311  null_chunk_row = Rast_allocate_null_buf();
312 
313  for (i_row = 0; i_row < nrows; i_row++) {
314  Rast_get_null_value_row(fd_patch_rast, null_chunk_row,
315  i_row + patch_bounds.north);
316 
317  for (i_col = 0; i_col < ncols; i_col++) {
318  patch_col = patch_bounds.west + i_col;
319 
320  if (null_chunk_row[patch_col] != 1)
321  patch_data[i_col] = 1 & 255;
322  else {
323  patch_data[i_col] = 0 & 255;
324  }
325  }
326 
327  fwrite(patch_data, sizeof(unsigned char),
328  (ncols) / sizeof(unsigned char), f_cat_rast);
329  if (ferror(f_cat_rast)) {
330  G_warning(
331  _("Unable to write into category raster conditions file <%s>"),
332  cat_rast);
333 
334  Rast_close(fd_patch_rast);
335  G_free(null_chunk_row);
336  fclose(f_cat_rast);
337 
338  return -1;
339  }
340  if (fseek(f_cat_rast, step_shift, SEEK_CUR) != 0) {
341  G_warning(_("Corrupted category raster conditions file <%s> "
342  "(fseek failed)"),
343  cat_rast);
344 
345  Rast_close(fd_patch_rast);
346  G_free(null_chunk_row);
347  fclose(f_cat_rast);
348 
349  return -1;
350  }
351  }
352 
353  Rast_close(fd_patch_rast);
354  G_free(null_chunk_row);
355  fclose(f_cat_rast);
356  return 0;
357 }
358 
359 /*!
360  \brief Updates scatter plots data in category by pixels which meets category
361  conditions.
362 
363  \param bands_rows data represents data describig one row from raster band
364  \param belongs_pix array which defines which pixels belongs to category
365  (1 value) and which not (0 value)
366  \param [out] scatts pointer to scScatts struct of type SC_SCATT_DATA,
367  which are modified according to values in belongs_pix
368  (represents scatter plot category)
369  */
370 static void update_cat_scatt_plts(struct rast_row *bands_rows,
371  unsigned short *belongs_pix,
372  struct scScatts *scatts)
373 {
374  int i_scatt, array_idx, i_chunk_rows_pix, max_arr_idx;
375 
376  CELL *b_1_row;
377  CELL *b_2_row;
378  char *b_1_null_row, *b_2_null_row;
379  struct rast_row b_1_rast_row, b_2_rast_row;
380 
381  struct Range b_1_range, b_2_range;
382  int b_1_range_size;
383 
384  int row_size = Rast_window_cols();
385 
386  int *scatts_bands = scatts->scatts_bands;
387 
388  for (i_scatt = 0; i_scatt < scatts->n_a_scatts; i_scatt++) {
389  b_1_rast_row = bands_rows[scatts_bands[i_scatt * 2]];
390  b_2_rast_row = bands_rows[scatts_bands[i_scatt * 2 + 1]];
391 
392  b_1_row = b_1_rast_row.row;
393  b_2_row = b_2_rast_row.row;
394 
395  b_1_null_row = b_1_rast_row.null_row;
396  b_2_null_row = b_2_rast_row.null_row;
397 
398  b_1_range = b_1_rast_row.rast_range;
399  b_2_range = b_2_rast_row.rast_range;
400 
401  b_1_range_size = b_1_range.max - b_1_range.min + 1;
402  max_arr_idx = (b_1_range.max - b_1_range.min + 1) *
403  (b_2_range.max - b_2_range.min + 1);
404 
405  for (i_chunk_rows_pix = 0; i_chunk_rows_pix < row_size;
406  i_chunk_rows_pix++) {
407  /* pixel does not belongs to scatter plot or has null value in one
408  * of the bands */
409  if (!belongs_pix[i_chunk_rows_pix] ||
410  b_1_null_row[i_chunk_rows_pix] == 1 ||
411  b_2_null_row[i_chunk_rows_pix] == 1)
412  continue;
413 
414  /* index in scatter plot array */
415  array_idx =
416  b_1_row[i_chunk_rows_pix] - b_1_range.min +
417  (b_2_row[i_chunk_rows_pix] - b_2_range.min) * b_1_range_size;
418 
419  if (array_idx < 0 || array_idx >= max_arr_idx) {
420  G_warning("Inconsistent data. Value computed for scatter plot "
421  "is out of initialized range.");
422  continue;
423  }
424 
425  /* increment scatter plot value */
426  ++scatts->scatts_arr[i_scatt]->scatt_vals_arr[array_idx];
427  }
428  }
429 }
430 
431 /*!
432  \brief Computes scatter plots data from bands_rows.
433 
434  \param scatt_conds pointer to scScatts struct of type SC_SCATT_CONDITIONS,
435  where are selected areas (conditions) stored
436  \param f_cats_rasts_conds file which stores selected areas (conditions) from
437  mapwindow see I_create_cat_rast and I_insert_patch_to_cat_rast
438  \param bands_rows data arrays of raster rows from analyzed raster bands
439  (all data in bands_rows and belongs_pix arrays represents same region (row))
440  \param[out] scatts pointer to scScatts struct of type SC_SCATT_DATA,
441  where are computed scatter plots stored
442  \param[out] fd_cats_rasts array of opened raster maps,
443  which every represents all selected pixels for category
444 
445  \return 0 on success
446  \return -1 on failure
447  */
448 static int compute_scatts_from_chunk_row(struct scCats *scatt_conds,
449  FILE **f_cats_rasts_conds,
450  struct rast_row *bands_rows,
451  struct scCats *scatts,
452  int *fd_cats_rasts)
453 {
454 
455  int i_rows_pix, i_cat, i_scatt, n_pixs;
456  int cat_id, scatt_plts_cat_idx, array_idx, max_arr_idx;
457  char *b_1_null_row, *b_2_null_row;
458  struct rast_row b_1_rast_row, b_2_rast_row;
459  CELL *cat_rast_row;
460 
461  struct scScatts *scatts_conds;
462  struct scScatts *scatts_scatt_plts;
463 
464  struct Range b_1_range, b_2_range;
465  int b_1_range_size;
466 
467  int *scatts_bands;
468 
469  CELL *b_1_row;
470  CELL *b_2_row;
471  unsigned char *i_scatt_conds;
472 
473  int row_size = Rast_window_cols();
474 
475  unsigned short *belongs_pix =
476  (unsigned short *)G_malloc(row_size * sizeof(unsigned short));
477  unsigned char *rast_pixs =
478  (unsigned char *)G_malloc(row_size * sizeof(unsigned char));
479  cat_rast_row = Rast_allocate_c_buf();
480 
481  for (i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++) {
482  scatts_conds = scatt_conds->cats_arr[i_cat];
483 
484  cat_id = scatt_conds->cats_ids[i_cat];
485 
486  scatt_plts_cat_idx = scatts->cats_idxs[cat_id];
487  if (scatt_plts_cat_idx < 0)
488  continue;
489  scatts_scatt_plts = scatts->cats_arr[scatt_plts_cat_idx];
490 
491  G_zero(belongs_pix, row_size * sizeof(unsigned short));
492 
493  /* if category has no conditions defined, scatter plots without
494  any constraint are computed (default scatter plots) */
495  if (!scatts_conds->n_a_scatts && !f_cats_rasts_conds[i_cat]) {
496  for (i_scatt = 0; i_scatt < scatts_scatt_plts->n_a_scatts;
497  i_scatt++) {
498  /* all pixels belongs */
499  for (i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)
500  belongs_pix[i_rows_pix] = 1;
501  }
502  }
503  /* compute belonging pixels for defined conditions */
504  else {
505  scatts_bands = scatts_conds->scatts_bands;
506 
507  /* check conditions from category raster conditions file
508  (see I_create_cat_rast) */
509  if (f_cats_rasts_conds[i_cat]) {
510  n_pixs = fread(rast_pixs, sizeof(unsigned char),
511  (row_size) / sizeof(unsigned char),
512  f_cats_rasts_conds[i_cat]);
513 
514  if (ferror(f_cats_rasts_conds[i_cat])) {
515  G_free(rast_pixs);
516  G_free(belongs_pix);
517  G_warning(_(
518  "Unable to read from category raster condition file."));
519  return -1;
520  }
521  if (n_pixs != (row_size) / (int)sizeof(unsigned char)) {
522  G_free(rast_pixs);
523  G_free(belongs_pix);
524  G_warning(
525  _("Invalid size of category raster conditions file."));
526  return -1;
527  }
528 
529  for (i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++) {
530  if (rast_pixs[i_rows_pix] != (0 & 255))
531  belongs_pix[i_rows_pix] = 1;
532  }
533  }
534 
535  /* check conditions defined in scatter plots */
536  for (i_scatt = 0; i_scatt < scatts_conds->n_a_scatts; i_scatt++) {
537  b_1_rast_row = bands_rows[scatts_bands[i_scatt * 2]];
538  b_2_rast_row = bands_rows[scatts_bands[i_scatt * 2 + 1]];
539 
540  b_1_row = b_1_rast_row.row;
541  b_2_row = b_2_rast_row.row;
542 
543  b_1_null_row = b_1_rast_row.null_row;
544  b_2_null_row = b_2_rast_row.null_row;
545 
546  b_1_range = b_1_rast_row.rast_range;
547  b_2_range = b_2_rast_row.rast_range;
548 
549  b_1_range_size = b_1_range.max - b_1_range.min + 1;
550  max_arr_idx = (b_1_range.max - b_1_range.min + 1) *
551  (b_2_range.max - b_2_range.min + 1);
552 
553  i_scatt_conds = scatts_conds->scatts_arr[i_scatt]->b_conds_arr;
554 
555  for (i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++) {
556  /* pixels already belongs to category from category raster
557  conditions file or contains null value in one of the
558  bands */
559  if (belongs_pix[i_rows_pix] ||
560  b_1_null_row[i_rows_pix] == 1 ||
561  b_2_null_row[i_rows_pix] == 1)
562  continue;
563 
564  array_idx =
565  b_1_row[i_rows_pix] - b_1_range.min +
566  (b_2_row[i_rows_pix] - b_2_range.min) * b_1_range_size;
567  if (array_idx < 0 || array_idx >= max_arr_idx) {
568  G_warning(_("Data inconsistent. "
569  "Value computed for scatter plot is out of "
570  "initialized range."));
571  continue;
572  }
573  /* pixels meets condition defined in scatter plot ->
574  belongs to scatter plot category */
575  if (i_scatt_conds[array_idx])
576  belongs_pix[i_rows_pix] = 1;
577  }
578  }
579  }
580 
581  /* update category raster with belonging pixels */
582  if (fd_cats_rasts[i_cat] >= 0) {
584 
585  for (i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)
586  if (belongs_pix[i_rows_pix])
587  cat_rast_row[i_rows_pix] = belongs_pix[i_rows_pix];
588 
589  Rast_put_c_row(fd_cats_rasts[i_cat], cat_rast_row);
590  }
591 
592  /* update scatter plots with belonging pixels */
593  update_cat_scatt_plts(bands_rows, belongs_pix, scatts_scatt_plts);
594  }
595 
596  G_free(cat_rast_row);
597  G_free(rast_pixs);
598  G_free(belongs_pix);
599 
600  return 0;
601 }
602 
603 /*!
604  \brief Get list of bands needed to be opened for analysis from scCats struct.
605  */
606 static void get_needed_bands(struct scCats *cats, int *b_needed_bands)
607 {
608  /* results in b_needed_bands - array of bools - if item has value 1,
609  band (defined by item index) is needed to be opened */
610  int i_cat, i_scatt;
611 
612  for (i_cat = 0; i_cat < cats->n_a_cats; i_cat++) {
613  for (i_scatt = 0; i_scatt < cats->cats_arr[i_cat]->n_a_scatts;
614  i_scatt++) {
615  G_debug(3, "Active scatt %d in catt %d", i_scatt, i_cat);
616 
617  b_needed_bands[cats->cats_arr[i_cat]->scatts_bands[i_scatt * 2]] =
618  1;
619  b_needed_bands[cats->cats_arr[i_cat]
620  ->scatts_bands[i_scatt * 2 + 1]] = 1;
621  }
622  }
623  return;
624 }
625 
626 /*!
627  \brief Helper function for clean up.
628  */
629 static void free_compute_scatts_data(int *fd_bands, struct rast_row *bands_rows,
630  int n_a_bands, int *bands_ids,
631  int *b_needed_bands, int *fd_cats_rasts,
632  FILE **f_cats_rasts_conds, int n_a_cats)
633 {
634  for (int i = 0; i < n_a_bands; i++) {
635  int band_id = bands_ids[i];
636  if (band_id >= 0) {
637  Rast_close(fd_bands[i]);
638  G_free(bands_rows[band_id].row);
639  G_free(bands_rows[band_id].null_row);
640  }
641  }
642 
643  for (int i = 0; i < n_a_cats; i++)
644  if (f_cats_rasts_conds[i])
645  fclose(f_cats_rasts_conds[i]);
646 
647  for (int i = 0; i < n_a_cats; i++)
648  if (fd_cats_rasts[i] >= 0)
649  Rast_close(fd_cats_rasts[i]);
650 
651  G_free(fd_bands);
652  G_free(bands_rows);
653  G_free(bands_ids);
654  G_free(b_needed_bands);
655  G_free(fd_cats_rasts);
656  G_free(f_cats_rasts_conds);
657 }
658 
659 /*!
660  \brief Compute scatter plots data.
661 
662  If category has not defined category raster condition file and no scatter
663  plot exists with condition, default/full scatter plot is computed. Warning:
664  calls Rast_set_window
665 
666  \param region analysis region, beaware that all input data must be prepared
667  for this region (bands (their ranges), cats_rasts_conds rasters...) \param
668  region function calls Rast_set_window for this region \param scatt_conds
669  pointer to scScatts struct of type SC_SCATT_CONDITIONS, where are stored
670  selected areas (conditions) in scatter plots \param cats_rasts_conds paths to
671  category raster conditions files representing selected areas from mapwindow
672  (conditions) in rasters for every category \param cats_rasts_conds index in
673  array represents corresponding category id \param cats_rasts_conds for
674  manipulation with category raster conditions file see also
675  I_id_scatt_to_bands and I_insert_patch_to_cat_rast \param bands names of
676  analyzed bands, order of bands is defined by their id \param n_bands number
677  of bands \param[out] scatts pointer to scScatts struct of type SC_SCATT_DATA,
678  where are computed scatter plots stored
679  \param[out] cats_rasts array of raster maps names for every category
680  where will be stored all selected pixels
681 
682  \return 0 on success
683  \return -1 on failure
684  */
685 int I_compute_scatts(struct Cell_head *region, struct scCats *scatt_conds,
686  const char **cats_rasts_conds, const char **bands,
687  int n_bands, struct scCats *scatts,
688  const char **cats_rasts)
689 {
690  const char *mapset;
691  char header[1024];
692 
693  int *fd_cats_rasts = G_malloc(scatt_conds->n_a_cats * sizeof(int));
694  FILE **f_cats_rasts_conds =
695  G_malloc(scatt_conds->n_a_cats * sizeof(FILE *));
696 
697  struct rast_row *bands_rows = G_malloc(n_bands * sizeof(struct rast_row));
698 
699  RASTER_MAP_TYPE data_type;
700  int nrows, i_band, n_a_bands, band_id;
701  int i_row, head_nchars, i_cat, id_cat;
702 
703  int *fd_bands = G_malloc(n_bands * sizeof(int));
704  int *bands_ids = G_malloc(n_bands * sizeof(int));
705  int *b_needed_bands = G_malloc(n_bands * sizeof(int));
706 
707  Rast_set_window(region);
708 
709  for (i_band = 0; i_band < n_bands; i_band++)
710  fd_bands[i_band] = -1;
711 
712  for (i_band = 0; i_band < n_bands; i_band++)
713  bands_ids[i_band] = -1;
714 
715  if (n_bands != scatts->n_bands || n_bands != scatt_conds->n_bands)
716  return -1;
717 
718  for (i_cat = 0; i_cat < scatts->n_a_cats; i_cat++)
719  fd_cats_rasts[i_cat] = -1;
720 
721  G_zero(b_needed_bands, (size_t)n_bands * sizeof(int));
722 
723  get_needed_bands(scatt_conds, &b_needed_bands[0]);
724  get_needed_bands(scatts, &b_needed_bands[0]);
725 
726  n_a_bands = 0;
727 
728  /* open band rasters, which are needed for computation */
729  for (band_id = 0; band_id < n_bands; band_id++) {
730  if (b_needed_bands[band_id]) {
731  G_debug(3, "Opening raster no. %d with name: %s", band_id,
732  bands[band_id]);
733 
734  if ((mapset = G_find_raster2(bands[band_id], "")) == NULL) {
735  free_compute_scatts_data(
736  fd_bands, bands_rows, n_a_bands, bands_ids, b_needed_bands,
737  fd_cats_rasts, f_cats_rasts_conds, scatt_conds->n_a_cats);
738  G_warning(_("Unable to find raster <%s>"), bands[band_id]);
739  return -1;
740  }
741 
742  if ((fd_bands[n_a_bands] = Rast_open_old(bands[band_id], mapset)) <
743  0) {
744  free_compute_scatts_data(
745  fd_bands, bands_rows, n_a_bands, bands_ids, b_needed_bands,
746  fd_cats_rasts, f_cats_rasts_conds, scatt_conds->n_a_cats);
747  G_warning(_("Unable to open raster <%s>"), bands[band_id]);
748  return -1;
749  }
750 
751  data_type = Rast_get_map_type(fd_bands[n_a_bands]);
752  if (data_type != CELL_TYPE) {
753  G_warning(_("Raster <%s> type is not <%s>"), bands[band_id],
754  "CELL");
755  return -1;
756  }
757 
758  bands_rows[band_id].row = Rast_allocate_c_buf();
759  bands_rows[band_id].null_row = Rast_allocate_null_buf();
760 
761  if (Rast_read_range(bands[band_id], mapset,
762  &bands_rows[band_id].rast_range) != 1) {
763  free_compute_scatts_data(
764  fd_bands, bands_rows, n_a_bands, bands_ids, b_needed_bands,
765  fd_cats_rasts, f_cats_rasts_conds, scatt_conds->n_a_cats);
766  G_warning(_("Unable to read range of raster <%s>"),
767  bands[band_id]);
768  return -1;
769  }
770 
771  bands_ids[n_a_bands] = band_id;
772  ++n_a_bands;
773  }
774  }
775 
776  /* open category rasters condition files and category rasters */
777  for (i_cat = 0; i_cat < scatts->n_a_cats; i_cat++) {
778  id_cat = scatts->cats_ids[i_cat];
779  if (cats_rasts[id_cat]) {
780  fd_cats_rasts[i_cat] = Rast_open_new(cats_rasts[id_cat], CELL_TYPE);
781  }
782 
783  if (cats_rasts_conds[id_cat]) {
784  f_cats_rasts_conds[i_cat] = fopen(cats_rasts_conds[id_cat], "r");
785  if (!f_cats_rasts_conds[i_cat]) {
786  free_compute_scatts_data(
787  fd_bands, bands_rows, n_a_bands, bands_ids, b_needed_bands,
788  fd_cats_rasts, f_cats_rasts_conds, scatt_conds->n_a_cats);
789  G_warning(
790  _("Unable to open category raster condition file <%s>"),
791  bands[band_id]);
792  return -1;
793  }
794  }
795  else
796  f_cats_rasts_conds[i_cat] = NULL;
797  }
798 
799  head_nchars = get_cat_rast_header(region, header);
800  for (i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
801  if (f_cats_rasts_conds[i_cat])
802  if (fseek(f_cats_rasts_conds[i_cat], head_nchars, SEEK_SET) != 0) {
803  G_warning(_("Corrupted category raster conditions file (fseek "
804  "failed)"));
805  return -1;
806  }
807 
808  nrows = Rast_window_rows();
809 
810  /* analyze bands by rows */
811  for (i_row = 0; i_row < nrows; i_row++) {
812  for (i_band = 0; i_band < n_a_bands; i_band++) {
813  band_id = bands_ids[i_band];
814  Rast_get_c_row(fd_bands[i_band], bands_rows[band_id].row, i_row);
815  Rast_get_null_value_row(fd_bands[i_band],
816  bands_rows[band_id].null_row, i_row);
817  }
818  if (compute_scatts_from_chunk_row(scatt_conds, f_cats_rasts_conds,
819  bands_rows, scatts,
820  fd_cats_rasts) == -1) {
821  free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, bands_ids,
822  b_needed_bands, fd_cats_rasts,
823  f_cats_rasts_conds, scatt_conds->n_a_cats);
824  return -1;
825  }
826  }
827  free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, bands_ids,
828  b_needed_bands, fd_cats_rasts, f_cats_rasts_conds,
829  scatt_conds->n_a_cats);
830  return 0;
831 }
832 
833 /*!
834  \brief Merge arrays according to opacity.
835  Every pixel in array must be represented by 4 values (RGBA).
836 
837  Implemented for speeding up of scatter plots rendering.
838 
839  \param merged_arr array which will be overlayd with overlay_arr
840  \param overlay_arr array to be merged_arr overlaid with
841  \param rows number of rows for the both arrays
842  \param cols number of columns for the both arrays
843  \param alpha transparency (0-1) of the overlay array for merging
844 
845  \return 0
846  */
847 int I_merge_arrays(unsigned char *merged_arr, unsigned char *overlay_arr,
848  unsigned rows, unsigned cols, double alpha)
849 {
850  unsigned int i_row, i_col, i_b;
851  unsigned int row_idx, col_idx, idx;
852  unsigned int c_a_i, c_a;
853 
854  for (i_row = 0; i_row < rows; i_row++) {
855  row_idx = i_row * cols;
856  for (i_col = 0; i_col < cols; i_col++) {
857  col_idx = 4 * (row_idx + i_col);
858  idx = col_idx + 3;
859 
860  c_a = overlay_arr[idx] * alpha;
861  c_a_i = 255 - c_a;
862 
863  merged_arr[idx] = (c_a_i * (int)merged_arr[idx] + c_a * 255) / 255;
864 
865  for (i_b = 0; i_b < 3; i_b++) {
866  idx = col_idx + i_b;
867  merged_arr[idx] = (c_a_i * (int)merged_arr[idx] +
868  c_a * (int)overlay_arr[idx]) /
869  255;
870  }
871  }
872  }
873  return 0;
874 }
875 
876 /*!
877  \brief Apply colromap to the raster.
878 
879  Implemented for speeding up of scatter plots rendering.
880 
881  \param vals array of values for applying the colormap
882  \param vals_mask mask of vals array
883  \param nvals number of items of vals_mask and vals array
884  \param colmap colour map to be applied
885  \param[out] col_vals output raster with applied color map (length is 4 *
886  nvals (RGBA))
887 
888  \return 0
889  */
890 int I_apply_colormap(unsigned char *vals, unsigned char *vals_mask,
891  unsigned nvals, unsigned char *colmap,
892  unsigned char *col_vals)
893 {
894  unsigned int i_val;
895  int v, i, i_cm;
896 
897  for (i_val = 0; i_val < nvals; i_val++) {
898  i_cm = 4 * i_val;
899 
900  v = vals[i_val];
901 
902  if (vals_mask && vals_mask[i_val])
903  for (i = 0; i < 4; i++)
904  col_vals[i_cm + i] = colmap[258 * 4 + i];
905  else if (v > 255)
906  for (i = 0; i < 4; i++)
907  col_vals[i_cm + i] = colmap[257 * 4 + i];
908  else if (v < 0)
909  for (i = 0; i < 4; i++)
910  col_vals[i_cm + i] = colmap[256 * 4 + i];
911  else
912  for (i = 0; i < 4; i++) {
913  col_vals[i_cm + i] = colmap[v * 4 + i];
914  }
915  }
916  return 0;
917 }
918 
919 /*!
920  \brief Wrapper for using of iclass perimeter rasterization by scatter plot.
921  Warning: calls Rast_set_window
922 
923  \param polygon array of polygon coordinates [x, y, x, y...]
924  \param pol_n_pts number of points in the polygon array
925  \param val value to be assigned to cells, which belong to plygon
926  \param rast_region region of raster
927  \param[out] rast raster to be pologyn rasterized in
928 
929  \return 0 on success
930  \return 1 on failure
931  */
932 
933 int I_rasterize(double *polygon, int pol_n_pts, unsigned char val,
934  struct Cell_head *rast_region, unsigned char *rast)
935 {
936  int i;
937  int x0, x1, y;
938  int row, row_idx, i_col;
939 
940  IClass_perimeter perimeter;
941 
942  struct line_pnts *pol;
943 
944  pol = Vect_new_line_struct();
945 
946  for (i = 0; i < pol_n_pts; i++) {
947  Vect_append_point(pol, polygon[i * 2], polygon[i * 2 + 1], 0.0);
948  }
949 
950  /* Rast_set_window(rast_region); */
951 
952  make_perimeter(pol, &perimeter, rast_region);
953  for (i = 1; i < perimeter.npoints; i += 2) {
954  y = perimeter.points[i].y;
955  if (y != perimeter.points[i - 1].y) {
956  G_warning(
957  _("prepare_signature: scan line %d has odd number of points."),
958  (i + 1) / 2);
959  return 1;
960  }
961 
962  x0 = perimeter.points[i - 1].x;
963  x1 = perimeter.points[i].x;
964 
965  if (x0 > x1) {
966  G_warning(_("signature: perimeter points out of order."));
967  return 1;
968  }
969 
970  row = (rast_region->rows - y);
971  if (row < 0 || row >= rast_region->rows) {
972  continue;
973  }
974 
975  row_idx = rast_region->cols * row;
976 
977  for (i_col = x0; i_col <= x1; i_col++) {
978  if (i_col < 0 || i_col >= rast_region->cols) {
979  continue;
980  }
981  rast[row_idx + i_col] = val;
982  }
983  }
984 
986  G_free(perimeter.points);
987  return 0;
988 }
#define NULL
Definition: ccmath.h:32
void G_zero(void *, int)
Zero out a buffer, buf, of length i.
Definition: gis/zero.c:23
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
void G_warning(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition: defs/gis.h:94
const char * G_find_raster2(const char *, const char *)
Find a raster map (look but don't touch)
Definition: find_rast.c:76
const char * G_find_raster(char *, const char *)
Find a raster map.
Definition: find_rast.c:55
int G_debug(int, const char *,...) __attribute__((format(printf
void Rast_close(int)
Close a raster map.
Definition: raster/close.c:99
int Rast_open_old(const char *, const char *)
Open an existing integer raster map (cell)
Definition: raster/open.c:112
void Rast_get_c_row(int, CELL *, int)
Get raster row (CELL type)
CELL * Rast_allocate_c_buf(void)
Allocate memory for a CELL type raster map.
Definition: alloc_cell.c:81
int Rast_open_new(const char *, RASTER_MAP_TYPE)
Opens a new raster map.
Definition: raster/open.c:1013
char * Rast_allocate_null_buf(void)
Allocates memory for a null buffer.
Definition: alloc_cell.c:120
int Rast_read_range(const char *, const char *, struct Range *)
Read raster range (CELL)
Definition: raster/range.c:160
int Rast_window_cols(void)
Number of columns in active window.
int Rast_window_rows(void)
Number of rows in active window.
Definition: raster/window.c:87
void Rast_set_null_value(void *, int, RASTER_MAP_TYPE)
To set one or more raster values to null.
Definition: null_val.c:98
void Rast_put_c_row(int, const CELL *)
Writes the next row for cell file (CELL version)
void Rast_set_window(struct Cell_head *)
Establishes 'window' as the current working window.
void Rast_get_cellhd(const char *, const char *, struct Cell_head *)
Read the raster header.
Definition: get_cellhd.c:41
void Rast_get_null_value_row(int, char *, int)
Read or simulate null value row.
RASTER_MAP_TYPE Rast_get_map_type(int)
Determine raster type from descriptor.
Definition: raster/open.c:932
void Vect_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
Definition: line.c:77
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition: line.c:45
int Vect_append_point(struct line_pnts *, double, double, double)
Appends one point to the end of a line.
Definition: line.c:148
#define GRASS_EPSILON
Definition: gis.h:173
int CELL
Definition: gis.h:629
#define _(str)
Definition: glocale.h:10
int make_perimeter(struct line_pnts *points, IClass_perimeter *perimeter, struct Cell_head *band_region)
Creates one perimeter from vector area.
int I_apply_colormap(unsigned char *vals, unsigned char *vals_mask, unsigned nvals, unsigned char *colmap, unsigned char *col_vals)
Apply colromap to the raster.
Definition: iscatt_core.c:890
int I_create_cat_rast(struct Cell_head *cat_rast_region, const char *cat_rast)
Create category raster conditions file. The file is used for holding selected areas from mapwindow....
Definition: iscatt_core.c:59
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)
Compute scatter plots data.
Definition: iscatt_core.c:685
int I_merge_arrays(unsigned char *merged_arr, unsigned char *overlay_arr, unsigned rows, unsigned cols, double alpha)
Merge arrays according to opacity. Every pixel in array must be represented by 4 values (RGBA).
Definition: iscatt_core.c:847
int I_rasterize(double *polygon, int pol_n_pts, unsigned char val, struct Cell_head *rast_region, unsigned char *rast)
Wrapper for using of iclass perimeter rasterization by scatter plot. Warning: calls Rast_set_window.
Definition: iscatt_core.c:933
int I_insert_patch_to_cat_rast(const char *patch_rast, struct Cell_head *cat_rast_region, const char *cat_rast)
Insert raster map patch into pgm file.
Definition: iscatt_core.c:231
#define CELL_TYPE
Definition: raster.h:11
int RASTER_MAP_TYPE
Definition: raster.h:25
2D/3D raster map header (used also for region)
Definition: gis.h:441
double ew_res
Resolution - east to west cell size for 2D data.
Definition: gis.h:477
double north
Extent coordinates (north)
Definition: gis.h:487
double east
Extent coordinates (east)
Definition: gis.h:491
double ns_res
Resolution - north to south cell size for 2D data.
Definition: gis.h:481
int rows
Number of rows for 2D data.
Definition: gis.h:456
int cols
Number of columns for 2D data.
Definition: gis.h:460
double south
Extent coordinates (south)
Definition: gis.h:489
double west
Extent coordinates (west)
Definition: gis.h:493
Definition: raster.h:220
Feature geometry info - coordinates.
Definition: dig_structs.h:1651
double * y
Array of Y coordinates.
Definition: dig_structs.h:1659
int * cats_ids
Definition: imagery.h:154
struct scScatts ** cats_arr
Definition: imagery.h:159
int n_a_cats
Definition: imagery.h:153
int * cats_idxs
Definition: imagery.h:156
int n_bands
Definition: imagery.h:149
int n_a_scatts
Definition: imagery.h:165
struct scdScattData ** scatts_arr
Definition: imagery.h:173
int * scatts_bands
Definition: imagery.h:167
unsigned int * scatt_vals_arr
Definition: imagery.h:186
unsigned char * b_conds_arr
Definition: imagery.h:183