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