GRASS 8 Programmer's Manual 8.6.0dev(2026)-ddeab64dbf
Loading...
Searching...
No Matches
raster/cats.c
Go to the documentation of this file.
1/*!
2 * \file lib/raster/cats.c
3 *
4 * \brief Raster Library - Raster categories management
5 *
6 * Code in this file works with category files. There are two formats:
7 * Pre 3.0 direct category encoding form:
8 *
9 * 2 categories
10 * Map Title
11 * Elevation: 1000.00 to 1005.00 feet
12 * Elevation: 1005.00 to 1010.00 feet
13 * Elevation: 1010.00 to 1015.00 feet
14 *
15 * 3.0 format
16 *
17 * # 2 categories
18 * Map Title
19 * Elevation: $1.2 to $2.2 feet ## Format Statement
20 * 5.0 1000 5.0 1005 ## Coefficients
21 *
22 * The coefficient line can be followed by explicit category labels
23 * which override the format label generation.
24 * 0:no data
25 * 2: .
26 * 5: . ## explicit category labels
27 * 7: .
28 * explicit labels can be also of the form:
29 * 5.5:5:9 label description
30 * or
31 * 15:30 label description
32 *
33 * In the format line
34 * $1 refers to the value num*5.0+1000 (ie, using the first 2 coefficients)
35 * $2 refers to the value num*5.0+1005 (ie, using the last 2 coefficients)
36 *
37 * $1.2 will print $1 with 2 decimal places.
38 *
39 * Also, the form $?xxx$yyy$ translates into yyy if the category is 1, xxx
40 * otherwise. The $yyy$ is optional. Thus
41 *
42 * $1 meter$?s
43 *
44 * will become: 1 meter (for category 1)
45 * 2 meters (for category 2), etc.
46 *
47 * The format and coefficients above would be used to generate the
48 * following statement in creation of the format appropriate category
49 * string for category "num":
50 *
51 * sprintf(buff,"Elevation: %.2f to %.2f feet", num*5.0+1000, num*5.0*1005)
52 *
53 * Note: while both the format and coefficient lines must be present
54 * a blank line for the fmt will effectively suppress automatic
55 * label generation
56 *
57 * Note: quant rules of Categories structures are heavily dependent
58 * on the fact that rules are stored in the same order they are entered.
59 * since i-th rule and i-th label are entered at the same time, we
60 * know that i-th rule maps fp range to i, thus we know for sure
61 * that cats.labels[i] corresponds to i-th quant rule
62 *
63 * (C) 2001-2009 by the GRASS Development Team
64 *
65 * This program is free software under the GNU General Public License
66 * (>=v2). Read the file COPYING that comes with GRASS for details.
67 *
68 * \author Original author CERL
69 */
70
71#include <stdlib.h>
72#include <string.h>
73
74#include <grass/gis.h>
75#include <grass/raster.h>
76#include <grass/glocale.h>
77
78static void get_cond(char **, char *, DCELL);
79static int get_fmt(char **, char *, int *);
80static int cmp(const void *, const void *);
81
82static void write_cats(const char *element, const char *name,
83 struct Categories *cats);
84static CELL read_cats(const char *element, const char *name, const char *mapset,
85 struct Categories *pcats, int full);
86
87static struct Categories save_cats;
88
89/*!
90 * \brief Read raster category file
91 *
92 * The category file for raster map <i>name</i> in <i>mapset</i> is
93 * read into the <i>cats</i> structure. If there is an error reading
94 * the category file, a diagnostic message is printed and -1 is
95 * returned. Otherwise, 0 is returned.
96 *
97 * \param name raster map name
98 * \param mapset mapset name
99 * \param[out] pcats pointer to Cats structure
100 *
101 * \return -1 on error
102 * \return 0 on success
103 */
104int Rast_read_cats(const char *name, const char *mapset,
105 struct Categories *pcats)
106{
107 switch (read_cats("cats", name, mapset, pcats, 1)) {
108 case -2:
109 G_warning(_("Category support for <%s@%s> missing"), name, mapset);
110 break;
111 case -1:
112 G_warning(_("Category support for <%s@%s> invalid"), name, mapset);
113 break;
114 default:
115 return 0;
116 }
117
118 return -1;
119}
120
121/*!
122 * \brief Read vector category file
123 *
124 * <b>Note:</b> This function works with <b>old</b> vector format.
125 *
126 * \todo: To be moved to the vector library
127 *
128 * The category file for vector map <i>name</i> in <i>mapset</i> is
129 * read into the <i>cats</i> structure. If there is an error reading
130 * the category file, a diagnostic message is printed and -1 is
131 * returned. Otherwise, 0 is returned.
132 *
133 * \param name vector map name
134 * \param mapset mapset name
135 * \param[out] pcats pointer to Cats structure
136 *
137 * \return -1 on error
138 * \return 0 on success
139 */
140int Rast_read_vector_cats(const char *name, const char *mapset,
141 struct Categories *pcats)
142{
143 switch (read_cats("dig_cats", name, mapset, pcats, 1)) {
144 case -2:
145 G_warning(_("Category support for vector map <%s@%s> missing"), name,
146 mapset);
147 break;
148 case -1:
149 G_warning(_("Category support for vector map <%s@%s> invalid"), name,
150 mapset);
151 break;
152 default:
153 return 0;
154 }
155
156 return -1;
157}
158
159/*!
160 \brief Get the max category number
161
162 Return the max category number of a raster map
163 of type CELL.
164
165 \param name raster map name
166 \param mapset mapset name
167
168 \return -1 on error
169 \return number of cats
170 */
171CELL Rast_get_max_c_cat(const char *name, const char *mapset)
172{
173 struct Range range;
174 CELL min, max;
175
176 /* return the max category number */
177 if (Rast_read_range(name, mapset, &range) < 0)
178 return -1;
179 Rast_get_range_min_max(&range, &min, &max);
181 max = 0;
182 return max;
183}
184
185static CELL read_cats(const char *element, const char *name, const char *mapset,
186 struct Categories *pcats, int full)
187{
188 FILE *fd;
189 char buff[1024];
190 CELL cat1, cat2;
191 DCELL val1, val2;
192 int old = 0, fp_map;
193 long num = -1;
194
195 if (strncmp(element, "dig", 3) == 0)
196 fp_map = 0;
197 else
198 fp_map = Rast_map_is_fp(name, mapset);
199
200 if (!(fd = G_fopen_old(element, name, mapset)))
201 return -2;
202
203 /* Read the number of categories */
204 if (G_getl(buff, sizeof buff, fd) == 0)
205 goto error;
206
207 if (sscanf(buff, "# %ld", &num) == 1)
208 old = 0;
209 else if (sscanf(buff, "%ld", &num) == 1)
210 old = 1;
211
212 if (!full) {
213 fclose(fd);
214 if (num < 0)
215 return 0; /* correct */
216 return (CELL)num;
217 }
218
219 /* Read the title for the file */
220 if (G_getl(buff, sizeof(buff), fd) == 0)
221 goto error;
222 G_strip(buff);
223 /* G_ascii_check(buff) ; */
224
225 Rast_init_cats(buff, pcats);
226 if (num >= 0)
227 pcats->num = num;
228
229 if (!old) {
230 char fmt[256];
231 float m1, a1, m2, a2;
232
233 if (G_getl(fmt, sizeof(fmt), fd) == 0)
234 goto error;
235 /* next line contains equation coefficients */
236 if (G_getl(buff, sizeof(buff), fd) == 0)
237 goto error;
238 if (sscanf(buff, "%f %f %f %f", &m1, &a1, &m2, &a2) != 4)
239 goto error;
240 Rast_set_cats_fmt(fmt, m1, a1, m2, a2, pcats);
241 }
242
243 /* Read all category names */
244 for (cat1 = 0;; cat1++) {
245 char label[1024];
246
247 if (G_getl(buff, sizeof(buff), fd) == 0)
248 break;
249 if (old)
250 Rast_set_c_cat(&cat1, &cat1, buff, pcats);
251 else {
252 *label = 0;
253 if (sscanf(buff, "%1s", label) != 1)
254 continue;
255 if (*label == '#')
256 continue;
257 *label = 0;
258 /* for fp maps try to read a range of data */
259 if (fp_map &&
260 sscanf(buff, "%lf:%lf:%[^\n]", &val1, &val2, label) == 3)
262 else if (!fp_map &&
263 sscanf(buff, "%d:%d:%[^\n]", &cat1, &cat2, label) == 3)
264 Rast_set_cat(&cat1, &cat2, label, pcats, CELL_TYPE);
265 else if (sscanf(buff, "%d:%[^\n]", &cat1, label) >= 1)
266 Rast_set_cat(&cat1, &cat1, label, pcats, CELL_TYPE);
267 else if (sscanf(buff, "%lf:%[^\n]", &val1, label) >= 1)
269 else
270 goto error;
271 }
272 }
273
274 fclose(fd);
275 return 0;
276error:
277 fclose(fd);
278 return -1;
279}
280
281/*!
282 * \brief Get title from category structure struct
283 *
284 * \todo Remove from GIS Library, replace by Rast_get_c_cats_title().
285 *
286 * Map layers store a one-line title in the category structure as
287 * well. This routine returns a pointer to the title contained in the
288 * <i>cats</i> structure. A legal pointer is always returned. If the
289 * map layer does not have a title, then a pointer to the empty string
290 * "" is returned.
291 *
292 * \param pcats pointer to Categories structure
293 *
294 * \return title
295 * \return "" if missing
296 */
298{
299 return pcats->title ? pcats->title : "";
300}
301
302/*!
303 * \brief Get a raster category label (CELL)
304 *
305 * This routine looks up category <i>rast</i> in the <i>pcats</i>
306 * structure and returns a pointer to a string which is the label for
307 * the category. A legal pointer is always returned. If the category
308 * does not exist in <i>pcats</i>, then a pointer to the empty string
309 * "" is returned.
310 *
311 * <b>Warning:</b> The pointer that is returned points to a hidden
312 * static buffer. Successive calls to Rast_get_c_cat() overwrite this
313 * buffer.
314 *
315 * \param rast cell value
316 * \param pcats pointer to Categories structure
317 *
318 * \return pointer to category label
319 * \return "" if category is not found
320 */
322{
324}
325
326/*!
327 * \brief Get a raster category label (FCELL)
328 *
329 * This routine looks up category <i>rast</i> in the <i>pcats</i>
330 * structure and returns a pointer to a string which is the label for
331 * the category. A legal pointer is always returned. If the category
332 * does not exist in <i>pcats</i>, then a pointer to the empty string
333 * "" is returned.
334 *
335 * <b>Warning:</b> The pointer that is returned points to a hidden
336 * static buffer. Successive calls to Rast_get_c_cat() overwrite this
337 * buffer.
338 *
339 * \param rast cell value
340 * \param pcats pointer to Categories structure
341 *
342 * \return pointer to category label
343 * \return "" if category is not found
344 */
346{
348}
349
350/*!
351 * \brief Get a raster category label (DCELL)
352 *
353 * This routine looks up category <i>rast</i> in the <i>pcats</i>
354 * structure and returns a pointer to a string which is the label for
355 * the category. A legal pointer is always returned. If the category
356 * does not exist in <i>pcats</i>, then a pointer to the empty string
357 * "" is returned.
358 *
359 * <b>Warning:</b> The pointer that is returned points to a hidden
360 * static buffer. Successive calls to Rast_get_c_cat() overwrite this
361 * buffer.
362 *
363 * \param rast cell value
364 * \param pcats pointer to Categories structure
365 *
366 * \return pointer to category label
367 * \return "" if category is not found
368 */
370{
372}
373
374/*!
375 * \brief Get a raster category label
376 *
377 * This routine looks up category <i>rast</i> in the <i>pcats</i>
378 * structure and returns a pointer to a string which is the label for
379 * the category. A legal pointer is always returned. If the category
380 * does not exist in <i>pcats</i>, then a pointer to the empty string
381 * "" is returned.
382 *
383 * <b>Warning:</b> The pointer that is returned points to a hidden
384 * static buffer. Successive calls to Rast_get_c_cat() overwrite this
385 * buffer.
386 *
387 * \param rast cell value
388 * \param pcats pointer to Categories structure
389 * \param data_type map type (CELL, FCELL, DCELL)
390 *
391 * \return pointer to category label
392 * \return "" if category is not found
393 */
394char *Rast_get_cat(void *rast, struct Categories *pcats,
395 RASTER_MAP_TYPE data_type)
396{
397 static char label[1024];
398 char *f, *l, *v;
399 CELL i;
400 DCELL val;
401 float a[2];
402 char fmt[30], value_str[30];
403
404 if (Rast_is_null_value(rast, data_type)) {
405 snprintf(label, sizeof(label), "no data");
406 return label;
407 }
408
409 /* first search the list of labels */
410 *label = 0;
411 val = Rast_get_d_value(rast, data_type);
412 i = Rast_quant_get_cell_value(&pcats->q, val);
413
414 G_debug(5, "Rast_get_cat(): val %lf found i %d", val, i);
415
416 if (!Rast_is_c_null_value(&i) && i < pcats->ncats) {
417 if (pcats->labels[i] != NULL)
418 return pcats->labels[i];
419 return label;
420 }
421
422 /* generate the label */
423 if ((f = pcats->fmt) == NULL)
424 return label;
425
426 a[0] = (float)val * pcats->m1 + pcats->a1;
427 a[1] = (float)val * pcats->m2 + pcats->a2;
428
429 l = label;
430 while (*f) {
431 if (*f == '$') {
432 f++;
433 if (*f == '$')
434 *l++ = *f++;
435 else if (*f == '?') {
436 f++;
437 get_cond(&f, v = value_str, val);
438 while (*v)
439 *l++ = *v++;
440 }
441 else if (get_fmt(&f, fmt, &i)) {
442 snprintf(v = value_str, sizeof(value_str), fmt, a[i]);
443 while (*v)
444 *l++ = *v++;
445 }
446 else
447 *l++ = '$';
448 }
449 else {
450 *l++ = *f++;
451 }
452 }
453 *l = 0;
454 return label;
455}
456
457/*!
458 * \brief Sets marks for all categories to 0.
459 *
460 * This initializes Categories structure for subsequent calls to
461 * Rast_mark_cats() for each row of data, where non-zero mark for
462 * i-th label means that some of the cells in rast_row are labeled
463 * with i-th label and fall into i-th data range. These marks help
464 * determine from the Categories structure which labels were used and
465 * which weren't.
466 *
467 * \param pcats pointer to Categories structure
468 */
470{
471 int i;
472
473 for (i = 0; i < pcats->ncats; i++)
474 pcats->marks[i] = 0;
475}
476
477/*!
478 * \brief Looks up the category label for each raster value (CELL).
479 *
480 * Looks up the category label for each raster value in the
481 * <i>rast_row</i> and updates the marks for labels found.
482 *
483 * <b>Note:</b> Non-zero mark for i-th label stores the number of of
484 * raster cells read so far which are labeled with i-th label and fall
485 * into i-th data range.
486 *
487 * \param rast_row raster row to update stats
488 * \param ncols number of columns
489 * \param pcats pointer to Categories structure
490 *
491 */
492void Rast_mark_c_cats(const CELL *rast_row, int ncols, struct Categories *pcats)
493{
494 Rast_mark_cats(rast_row, ncols, pcats, CELL_TYPE);
495}
496
497/*!
498 * \brief Looks up the category label for each raster value (FCELL).
499 *
500 * Looks up the category label for each raster value in the
501 * <i>rast_row</i> and updates the marks for labels found.
502 *
503 * <b>Note:</b> Non-zero mark for i-th label stores the number of of
504 * raster cells read so far which are labeled with i-th label and fall
505 * into i-th data range.
506 *
507 * \param rast_row raster row to update stats
508 * \param ncols number of columns
509 * \param pcats pointer to Categories structure
510 *
511 */
512void Rast_mark_f_cats(const FCELL *rast_row, int ncols,
513 struct Categories *pcats)
514{
515 Rast_mark_cats(rast_row, ncols, pcats, FCELL_TYPE);
516}
517
518/*!
519 * \brief Looks up the category label for each raster value (DCELL).
520 *
521 * Looks up the category label for each raster value in the
522 * <i>rast_row</i> and updates the marks for labels found.
523 *
524 * <b>Note:</b> Non-zero mark for i-th label stores the number of of
525 * raster cells read so far which are labeled with i-th label and fall
526 * into i-th data range.
527 *
528 * \param rast_row raster row to update stats
529 * \param ncols number of columns
530 * \param pcats pointer to Categories structure
531 *
532 */
533void Rast_mark_d_cats(const DCELL *rast_row, int ncols,
534 struct Categories *pcats)
535{
536 Rast_mark_cats(rast_row, ncols, pcats, DCELL_TYPE);
537}
538
539/*!
540 * \brief Looks up the category label for each raster value (DCELL).
541 *
542 * Looks up the category label for each raster value in the
543 * <i>rast_row</i> and updates the marks for labels found.
544 *
545 * <b>Note:</b> Non-zero mark for i-th label stores the number of of
546 * raster cells read so far which are labeled with i-th label and fall
547 * into i-th data range.
548 *
549 * \param rast_row raster row to update stats
550 * \param ncols number of columns
551 * \param pcats pointer to Categories structure
552 * \param data_type map type
553 *
554 * \return -1 on error
555 * \return 1 on success
556 */
557int Rast_mark_cats(const void *rast_row, int ncols, struct Categories *pcats,
558 RASTER_MAP_TYPE data_type)
559{
560 size_t size = Rast_cell_size(data_type);
561 CELL i;
562
563 while (ncols-- > 0) {
565 Rast_get_d_value(rast_row, data_type));
566 if (Rast_is_c_null_value(&i))
567 continue;
568 if (i > pcats->ncats)
569 return -1;
570 pcats->marks[i]++;
571 rast_row = G_incr_void_ptr(rast_row, size);
572 }
573 return 1;
574}
575
576/*!
577 * \brief Rewind raster categories
578 *
579 * After call to this function Rast_get_next_marked_cat() returns
580 * the first marked cat label.
581 *
582 * \param pcats pointer to Categories structure
583 */
585{
586 pcats->last_marked_rule = -1;
587}
588
589/*!
590 \brief Get next marked raster categories (DCELL)
591
592 \param pcats pointer to Categories structure
593 \param rast1, rast2 cell values (raster range)
594 \param[out] count count
595
596 \return NULL if not found
597 \return description if found
598 */
600 DCELL *rast2, long *count)
601{
602 char *descr = NULL;
603 int found, i;
604
605 found = 0;
606 /* pcats->ncats should be == Rast_quant_nof_rules(&pcats->q) */
607
608 G_debug(3, "last marked %d nrules %d\n", pcats->last_marked_rule,
610
611 for (i = pcats->last_marked_rule + 1; i < Rast_quant_nof_rules(&pcats->q);
612 i++) {
613 descr = Rast_get_ith_d_cat(pcats, i, rast1, rast2);
614 G_debug(5, "%d %d", i, pcats->marks[i]);
615 if (pcats->marks[i]) {
616 found = 1;
617 break;
618 }
619 }
620
621 if (!found)
622 return NULL;
623
624 *count = pcats->marks[i];
625 pcats->last_marked_rule = i;
626 return descr;
627}
628
629/*!
630 \brief Get next marked raster categories (CELL)
631
632 \param pcats pointer to Categories structure
633 \param rast1, rast2 cell values (raster range)
634 \param[out] count count
635
636 \return NULL if not found
637 \return description if found
638 */
644
645/*!
646 \brief Get next marked raster categories (FCELL)
647
648 \param pcats pointer to Categories structure
649 \param rast1, rast2 cell values (raster range)
650 \param[out] count count
651
652 \return NULL if not found
653 \return description if found
654 */
660
661/*!
662 \brief Get next marked raster categories
663
664 \param pcats pointer to Categories structure
665 \param rast1, rast2 cell values (raster range)
666 \param[out] count count
667 \param data_type map type
668
669 \return NULL if not found
670 \return description if found
671 */
673 void *rast2, long *count,
674 RASTER_MAP_TYPE data_type)
675{
676 DCELL val1, val2;
677 char *lab;
678
680 Rast_set_d_value(rast1, val1, data_type);
681 Rast_set_d_value(rast2, val2, data_type);
682 return lab;
683}
684
685static int get_fmt(char **f, char *fmt, int *i)
686{
687 char *ff;
688
689 ff = *f;
690 if (*ff == 0)
691 return 0;
692 if (*ff == '$') {
693 *f = ff + 1;
694 return 0;
695 }
696 switch (*ff++) {
697 case '1':
698 *i = 0;
699 break;
700 case '2':
701 *i = 1;
702 break;
703 default:
704 return 0;
705 }
706 *fmt++ = '%';
707 *fmt++ = '.';
708 if (*ff++ != '.') {
709 *f = ff - 1;
710 *fmt++ = '0';
711 *fmt++ = 'f';
712 *fmt = 0;
713 return 1;
714 }
715 *fmt = '0';
716 while (*ff >= '0' && *ff <= '9')
717 *fmt++ = *ff++;
718 *fmt++ = 'f';
719 *fmt = 0;
720 *f = ff;
721 return 1;
722}
723
724static void get_cond(char **f, char *value, DCELL val)
725{
726 char *ff;
727
728 ff = *f;
729 if (val == 1.) {
730 while (*ff)
731 if (*ff++ == '$')
732 break;
733 }
734
735 while (*ff)
736 if (*ff == '$') {
737 ff++;
738 break;
739 }
740 else
741 *value++ = *ff++;
742
743 if (val != 1.) {
744 while (*ff)
745 if (*ff++ == '$')
746 break;
747 }
748 *value = 0;
749 *f = ff;
750}
751
752/*!
753 * \brief Set a raster category label (CELL)
754 *
755 * Adds the label for range <i>rast1</i> through <i>rast2</i> in
756 * category structure <i>pcats</i>.
757 *
758 * \param rast1, rast2 raster values (range)
759 * \param label category label
760 * \param pcats pointer to Categories structure
761 *
762 * \return -1 on error
763 * \return 0 if null value detected
764 * \return 1 on success
765 */
766int Rast_set_c_cat(const CELL *rast1, const CELL *rast2, const char *label,
767 struct Categories *pcats)
768{
769 return Rast_set_cat(rast1, rast2, label, pcats, CELL_TYPE);
770}
771
772/*!
773 * \brief Set a raster category label (FCELL)
774 *
775 * Adds the label for range <i>rast1</i> through <i>rast2</i> in
776 * category structure <i>pcats</i>.
777 *
778 * \param rast1, rast2 raster values (range)
779 * \param label category label
780 * \param pcats pointer to Categories structure
781 *
782 * \return
783 */
784int Rast_set_f_cat(const FCELL *rast1, const FCELL *rast2, const char *label,
785 struct Categories *pcats)
786{
787 return Rast_set_cat(rast1, rast2, label, pcats, FCELL_TYPE);
788}
789
790/*!
791 * \brief Set a raster category label (DCELL)
792 *
793 * Adds the label for range <i>rast1</i> through <i>rast2</i> in
794 * category structure <i>pcats</i>.
795 *
796 * \param rast1, rast2 raster values (range)
797 * \param label category label
798 * \param pcats pointer to Categories structure
799 *
800 * \return -1 on error
801 * \return 0 if null value detected
802 * \return 1 on success
803 */
804int Rast_set_d_cat(const DCELL *rast1, const DCELL *rast2, const char *label,
805 struct Categories *pcats)
806{
807 long len;
809 int i;
810
811 /* DEBUG fprintf(stderr,"Rast_set_d_cat(rast1 = %p,rast2 = %p,label =
812 '%s',pcats = %p)\n", rast1,rast2,label,pcats); */
814 return 0;
816 return 0;
817 /* DEBUG fprintf (stderr, "Rast_set_d_cat(): adding quant rule: %f %f %d
818 * %d\n", *rast1, *rast2, pcats->ncats, pcats->ncats); */
819 /* the set_cat() functions are used in many places to reset the labels
820 for the range (or cat) with existing label. In this case we don't
821 want to store both rules with identical range even though the result
822 of get_cat() will be correct, since it will use rule added later.
823 we don't want to overuse memory and we don't want rules which are
824 not used to be written out in cats file. So we first look if
825 the label for this range has been sen, and if it has, overwrite it */
826
827 for (i = 0; i < pcats->ncats; i++) {
829 if ((dtmp1 == *rast1 && dtmp2 == *rast2) ||
830 (dtmp1 == *rast2 && dtmp2 == *rast1)) {
831 if (pcats->labels[i] != NULL)
832 G_free(pcats->labels[i]);
833 pcats->labels[i] = G_store(label);
834 G_newlines_to_spaces(pcats->labels[i]);
835 G_strip(pcats->labels[i]);
836 return 1;
837 }
838 }
839 /* when rule for this range does not exist */
840 /* DEBUG fprintf (stderr, "Rast_set_d_cat(): New rule: adding %d %p\n", i,
841 * pcats->labels); */
842 Rast_quant_add_rule(&pcats->q, *rast1, *rast2, pcats->ncats, pcats->ncats);
843 pcats->ncats++;
844 if (pcats->nalloc < pcats->ncats) {
845 /* DEBUG fprintf (stderr, "Rast_set_d_cat(): need more space nalloc = %d
846 * ncats = %d\n", pcats->nalloc,pcats->ncats); */
847 len = (pcats->nalloc + 256) * sizeof(char *);
848 /* DEBUG fprintf (stderr, "Rast_set_d_cat(): allocating %d
849 * labels(%d)\n", pcats->nalloc + 256,(int)len); */
850 if (len != (int)len) { /* make sure len doesn't overflow int */
851 pcats->ncats--;
852 return -1;
853 }
854 /* DEBUG fprintf(stderr,"Rast_set_d_cat(): pcats->nalloc = %d,
855 * pcats->labels = (%p), len =
856 * %d\n",pcats->nalloc,pcats->labels,(int)len); */
857 if (pcats->nalloc) {
858 /* DEBUG fprintf(stderr,"Rast_set_d_cat(): Realloc-ing pcats->labels
859 * (%p)\n",pcats->labels); */
860 pcats->labels = (char **)G_realloc((char *)pcats->labels, (int)len);
861 }
862 else {
863 /* DEBUG fprintf(stderr,"Rast_set_d_cat(): alloc-ing new labels
864 * pointer array\n"); */
865 pcats->labels = (char **)G_malloc((int)len);
866 }
867 /* fflush(stderr); */
868 /* DEBUG fprintf (stderr, "Rast_set_d_cats(): allocating %d
869 * marks(%d)\n", pcats->nalloc + 256,(int)len); */
870 len = (pcats->nalloc + 256) * sizeof(int);
871 if (len != (int)len) { /* make sure len doesn't overflow int */
872 pcats->ncats--;
873 return -1;
874 }
875 if (pcats->nalloc)
876 pcats->marks = (int *)G_realloc((char *)pcats->marks, (int)len);
877 else
878 pcats->marks = (int *)G_malloc((int)len);
879 pcats->nalloc += 256;
880 }
881 /* DEBUG fprintf(stderr,"Rast_set_d_cats(): store new label\n"); */
882 pcats->labels[pcats->ncats - 1] = G_store(label);
883 G_newlines_to_spaces(pcats->labels[pcats->ncats - 1]);
884 G_strip(pcats->labels[pcats->ncats - 1]);
885 /* DEBUG
886 fprintf (stderr, "%d %s\n", pcats->ncats - 1, pcats->labels[pcats->ncats
887 - 1]);
888 */
889 /* updates cats.num = max cat values. This is really just used in old
890 raster programs, and I am doing it for backwards cmpatibility (Olga) */
891 if ((CELL)*rast1 > pcats->num)
892 pcats->num = (CELL)*rast1;
893 if ((CELL)*rast2 > pcats->num)
894 pcats->num = (CELL)*rast2;
895 /* DEBUG fprintf(stderr,"Rast_set_d_cat(): done\n"); */
896 /* DEBUG fflush(stderr); */
897 return 1;
898}
899
900/*!
901 * \brief Set a raster category label
902 *
903 * Adds the label for range <i>rast1</i> through <i>rast2</i> in
904 * category structure <i>pcats</i>.
905 *
906 * \param rast1, rast2 raster values (range)
907 * \param label category label
908 * \param pcats pointer to Categories structure
909 * \param data_type map type
910 *
911 * \return -1 on error
912 * \return 0 if null value detected
913 * \return 1 on success
914 */
915int Rast_set_cat(const void *rast1, const void *rast2, const char *label,
916 struct Categories *pcats, RASTER_MAP_TYPE data_type)
917{
918 DCELL val1, val2;
919
920 val1 = Rast_get_d_value(rast1, data_type);
921 val2 = Rast_get_d_value(rast2, data_type);
922 return Rast_set_d_cat(&val1, &val2, label, pcats);
923}
924
925/*!
926 * \brief Write raster category file
927 *
928 * \todo To be removed, replaced by Rast_write_cats().
929 *
930 * Writes the category file for the raster map <i>name</i> in the
931 * current mapset from the <i>cats</i> structure.
932 *
933 * \param name map name
934 * \param cats pointer to Categories structure
935 *
936 * \return void
937 */
938void Rast_write_cats(const char *name, struct Categories *cats)
939{
940 write_cats("cats", name, cats);
941}
942
943/*!
944 * \brief Write vector category file
945 *
946 * <b>Note:</b> Used for only old vector format!
947 *
948 * \todo Move to the vector library.
949 *
950 * \param name map name
951 * \param cats pointer to Categories structure
952 *
953 * \return void
954 */
955void Rast_write_vector_cats(const char *name, struct Categories *cats)
956{
957 write_cats("dig_cats", name, cats);
958}
959
960static void write_cats(const char *element, const char *name,
961 struct Categories *cats)
962{
963 FILE *fd;
964 int i, fp_map;
965 char *descr;
966 DCELL val1, val2;
967 char str1[100], str2[100];
968
969 fd = G_fopen_new(element, name);
970 if (!fd)
971 G_fatal_error(_("Unable to open %s file for map <%s>"), element, name);
972
973 /* write # cats - note # indicate 3.0 or later */
974 fprintf(fd, "# %ld categories\n", (long)cats->num);
975
976 /* title */
977 fprintf(fd, "%s\n", cats->title != NULL ? cats->title : "");
978
979 /* write format and coefficients */
980 fprintf(fd, "%s\n", cats->fmt != NULL ? cats->fmt : "");
981 fprintf(fd, "%.2f %.2f %.2f %.2f\n", cats->m1, cats->a1, cats->m2,
982 cats->a2);
983
984 /* if the map is integer or if this is a vector map, sort labels */
985 if (strncmp(element, "dig", 3) == 0)
986 fp_map = 0;
987 else
989 if (!fp_map)
990 Rast_sort_cats(cats);
991
992 /* write the cat numbers:label */
993 for (i = 0; i < Rast_quant_nof_rules(&cats->q); i++) {
994 descr = Rast_get_ith_d_cat(cats, i, &val1, &val2);
995 if ((cats->fmt && cats->fmt[0]) || (descr && descr[0])) {
996 if (val1 == val2) {
997 snprintf(str1, sizeof(str1), "%.10f", val1);
999 fprintf(fd, "%s:%s\n", str1, descr != NULL ? descr : "");
1000 }
1001 else {
1002 snprintf(str1, sizeof(str1), "%.10f", val1);
1004 snprintf(str2, sizeof(str2), "%.10f", val2);
1006 fprintf(fd, "%s:%s:%s\n", str1, str2,
1007 descr != NULL ? descr : "");
1008 }
1009 }
1010 }
1011 fclose(fd);
1012}
1013
1014/*!
1015 * \brief Get category description (DCELL)
1016 *
1017 * Returns i-th description and i-th data range from the list of
1018 * category descriptions with corresponding data ranges. end points of
1019 * data interval in <i>rast1</i> and <i>rast2</i>.
1020 *
1021 * \param pcats pointer to Categories structure
1022 * \param i index
1023 * \param rast1, rast2 raster values (range)
1024 *
1025 * \return "" on error
1026 * \return pointer to category description
1027 */
1028char *Rast_get_ith_d_cat(const struct Categories *pcats, int i, DCELL *rast1,
1029 DCELL *rast2)
1030{
1031 int index;
1032
1033 if (i > pcats->ncats) {
1036 return "";
1037 }
1038 Rast_quant_get_ith_rule(&pcats->q, i, rast1, rast2, &index, &index);
1039 return pcats->labels[index];
1040}
1041
1042/*!
1043 * \brief Get category description (FCELL)
1044 *
1045 * Returns i-th description and i-th data range from the list of
1046 * category descriptions with corresponding data ranges. end points of
1047 * data interval in <i>rast1</i> and <i>rast2</i>.
1048 *
1049 * \param pcats pointer to Categories structure
1050 * \param i index
1051 * \param rast1, rast2 raster values (range)
1052 *
1053 * \return "" on error
1054 * \return pointer to category description
1055 */
1056char *Rast_get_ith_f_cat(const struct Categories *pcats, int i, void *rast1,
1057 void *rast2)
1058{
1059 RASTER_MAP_TYPE data_type = FCELL_TYPE;
1060 char *tmp;
1061 DCELL val1, val2;
1062
1063 tmp = Rast_get_ith_d_cat(pcats, i, &val1, &val2);
1064 Rast_set_d_value(rast1, val1, data_type);
1065 Rast_set_d_value(rast2, val2, data_type);
1066 return tmp;
1067}
1068
1069/*!
1070 * \brief Get category description (CELL)
1071 *
1072 * Returns i-th description and i-th data range from the list of
1073 * category descriptions with corresponding data ranges. end points of
1074 * data interval in <i>rast1</i> and <i>rast2</i>.
1075 *
1076 * \param pcats pointer to Categories structure
1077 * \param i index
1078 * \param rast1, rast2 raster values (range)
1079 *
1080 * \return "" on error
1081 * \return pointer to category description
1082 */
1083char *Rast_get_ith_c_cat(const struct Categories *pcats, int i, void *rast1,
1084 void *rast2)
1085{
1086 RASTER_MAP_TYPE data_type = CELL_TYPE;
1087 char *tmp;
1088 DCELL val1, val2;
1089
1090 tmp = Rast_get_ith_d_cat(pcats, i, &val1, &val2);
1091 Rast_set_d_value(rast1, val1, data_type);
1092 Rast_set_d_value(rast2, val2, data_type);
1093 return tmp;
1094}
1095
1096/*!
1097 * \brief Get category description
1098 *
1099 * Returns i-th description and i-th data range from the list of
1100 * category descriptions with corresponding data ranges. end points of
1101 * data interval in <i>rast1</i> and <i>rast2</i>.
1102 *
1103 * \param pcats pointer to Categories structure
1104 * \param i index
1105 * \param rast1, rast2 raster values (range)
1106 * \param data_type map type
1107 *
1108 * \return "" on error
1109 * \return pointer to category description
1110 */
1111char *Rast_get_ith_cat(const struct Categories *pcats, int i, void *rast1,
1112 void *rast2, RASTER_MAP_TYPE data_type)
1113{
1114 char *tmp;
1115 DCELL val1, val2;
1116
1117 tmp = Rast_get_ith_d_cat(pcats, i, &val1, &val2);
1118 Rast_set_d_value(rast1, val1, data_type);
1119 Rast_set_d_value(rast2, val2, data_type);
1120 return tmp;
1121}
1122
1123/*!
1124 * \brief Initialize category structure
1125 *
1126 * To construct a new category file, the structure must first be
1127 * initialized. This routine initializes the <i>cats</i> structure,
1128 * and copies the <i>title</i> into the structure. The number of
1129 * categories is set initially to <i>n</i>.
1130 *
1131 * For example:
1132 \code
1133 struct Categories cats;
1134 Rast_init_cats ("", &cats);
1135 \endcode
1136 *
1137 * \todo Eliminate pcats->num. Num has no meaning in new Categories
1138 * structure and only stores (int) largest data value for backwards
1139 * compatibility.
1140 *
1141 * \param title title
1142 * \param pcats pointer to Categories structure
1143 */
1144void Rast_init_cats(const char *title, struct Categories *pcats)
1145{
1146 Rast_set_cats_title(title, pcats);
1147 pcats->labels = NULL;
1148 pcats->nalloc = 0;
1149 pcats->ncats = 0;
1150 pcats->num = 0;
1151 pcats->fmt = NULL;
1152 pcats->m1 = 0.0;
1153 pcats->a1 = 0.0;
1154 pcats->m2 = 0.0;
1155 pcats->a2 = 0.0;
1156 pcats->last_marked_rule = -1;
1158}
1159
1160/*!
1161 * \brief Set title in category structure
1162 *
1163 * \todo To be removed, replaced by Rast_set_cats_title().
1164 *
1165 * The <i>title</i> is copied into the <i>pcats</i> structure.
1166 *
1167 * \param title title
1168 * \param pcats pointer to Categories structure
1169 */
1170void Rast_set_cats_title(const char *title, struct Categories *pcats)
1171{
1172 if (title == NULL)
1173 title = "";
1174 pcats->title = G_store(title);
1176 G_strip(pcats->title);
1177}
1178
1179/*!
1180 \brief Set category fmt (?)
1181
1182 \param fmt
1183 \param m1
1184 \param a1
1185 \param m2
1186 \param a2
1187 \param pcats pointer to Categories structure
1188 */
1189void Rast_set_cats_fmt(const char *fmt, double m1, double a1, double m2,
1190 double a2, struct Categories *pcats)
1191{
1192 pcats->m1 = m1;
1193 pcats->a1 = a1;
1194 pcats->m2 = m2;
1195 pcats->a2 = a2;
1196
1197 pcats->fmt = G_store(fmt);
1199 G_strip(pcats->fmt);
1200}
1201
1202/*!
1203 * \brief Free category structure memory
1204 *
1205 * \todo To be removed, replaced by Rast_free_cats().
1206 *
1207 * Frees memory allocated by Rast_read_cats(), Rast_init_cats() and
1208 * Rast_set_c_cat().
1209 *
1210 * \param pcats pointer to Categories structure
1211 */
1213{
1214 int i;
1215
1216 if (pcats->title != NULL) {
1217 G_free(pcats->title);
1218 pcats->title = NULL;
1219 }
1220 if (pcats->fmt != NULL) {
1221 G_free(pcats->fmt);
1222 pcats->fmt = NULL;
1223 }
1224 if (pcats->ncats > 0) {
1225 for (i = 0; i < pcats->ncats; i++)
1226 if (pcats->labels[i] != NULL)
1227 G_free(pcats->labels[i]);
1228 G_free(pcats->labels);
1229 G_free(pcats->marks);
1230 pcats->labels = NULL;
1231 }
1233 pcats->ncats = 0;
1234 pcats->nalloc = 0;
1235}
1236
1237/*!
1238 * \brief Copy raster categories
1239 *
1240 * Allocates NEW space for quant rules and labels n <i>pcats_to</i>
1241 * and copies all info from <i>pcats_from</i> cats to
1242 * <i>pcats_to</i> cats.
1243 *
1244 * \param pcats_to pointer to destination Categories structure
1245 * \param pcats_from pointer to source Categories structure
1246 */
1248 const struct Categories *pcats_from)
1249{
1250 int i;
1251 char *descr;
1252 DCELL d1, d2;
1253
1255 for (i = 0; i < pcats_from->ncats; i++) {
1256 descr = Rast_get_ith_d_cat(pcats_from, i, &d1, &d2);
1257 Rast_set_d_cat(&d1, &d2, descr, pcats_to);
1258 }
1259}
1260
1261/*!
1262 \brief Get number of raster categories
1263
1264 \param pcats pointer to Categories structure
1265
1266 \return number of categories
1267 */
1269{
1270 return pcats->ncats;
1271}
1272
1273/*!
1274 \brief Sort categories
1275
1276 \param pcats pointer to Categories structure
1277
1278 \return -1 on error (nothing to sort)
1279 \return 0 on success
1280 */
1282{
1283 int *indexes, i, ncats;
1284 char *descr;
1285 DCELL d1, d2;
1286
1287 if (pcats->ncats <= 1)
1288 return -1;
1289
1290 ncats = pcats->ncats;
1291 G_debug(3, "Rast_sort_cats(): Copying to save cats buffer");
1292 Rast_copy_cats(&save_cats, pcats);
1294
1295 indexes = (int *)G_malloc(sizeof(int) * ncats);
1296 for (i = 0; i < ncats; i++)
1297 indexes[i] = i;
1298
1299 qsort(indexes, ncats, sizeof(int), cmp);
1300 Rast_init_cats(save_cats.title, pcats);
1301 for (i = 0; i < ncats; i++) {
1302 descr = Rast_get_ith_d_cat(&save_cats, indexes[i], &d1, &d2);
1303 G_debug(4, " Write sorted cats, pcats = %p pcats->labels = %p",
1304 (void *)pcats, (void *)pcats->labels);
1305 Rast_set_d_cat(&d1, &d2, descr, pcats);
1306 }
1307 Rast_free_cats(&save_cats);
1308 G_free(indexes);
1309
1310 return 0;
1311}
1312
1313static int cmp(const void *aa, const void *bb)
1314{
1315 const int *a = aa, *b = bb;
1317 CELL index;
1318
1319 Rast_quant_get_ith_rule(&(save_cats.q), *a, &min_rast1, &max_rast1, &index,
1320 &index);
1321 Rast_quant_get_ith_rule(&(save_cats.q), *b, &min_rast2, &max_rast2, &index,
1322 &index);
1323 if (min_rast1 < min_rast2)
1324 return -1;
1325 if (min_rast1 > min_rast2)
1326 return 1;
1327 return 0;
1328}
#define NULL
Definition ccmath.h:32
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:147
#define G_realloc(p, n)
Definition defs/gis.h:141
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
FILE * G_fopen_new(const char *, const char *)
Open a new database file.
Definition gis/open.c:221
void G_newlines_to_spaces(char *)
Definition nl_to_spaces.c:3
#define G_malloc(n)
Definition defs/gis.h:139
FILE * G_fopen_old(const char *, const char *, const char *)
Open a database file for reading.
Definition gis/open.c:253
void G_trim_decimal(char *)
Removes trailing zeros from decimal number.
Definition trim_dec.c:24
void G_strip(char *)
Removes all leading and trailing white space from string.
Definition strings.c:300
#define G_incr_void_ptr(ptr, size)
Definition defs/gis.h:81
char * G_store(const char *)
Copy string to allocated memory.
Definition strings.c:87
int G_getl(char *, int, FILE *)
Gets a line of text from a file.
Definition getl.c:33
int G_debug(int, const char *,...) __attribute__((format(printf
const char * G_mapset(void)
Get current mapset name.
Definition gis/mapset.c:33
int Rast_is_null_value(const void *, RASTER_MAP_TYPE)
To check if a raster value is set to NULL.
Definition null_val.c:176
CELL Rast_quant_get_cell_value(struct Quant *, DCELL)
Returns a CELL category for the floating-point value based on the quantization rules in q....
Definition quant.c:592
void Rast_quant_free(struct Quant *)
Resets and frees allocated memory.
Definition quant.c:55
void Rast_set_d_null_value(DCELL *, int)
To set a number of DCELL raster values to NULL.
Definition null_val.c:153
void Rast_set_d_value(void *, DCELL, RASTER_MAP_TYPE)
Places a DCELL raster value.
void Rast_quant_add_rule(struct Quant *, DCELL, DCELL, CELL, CELL)
Adds a new rule to the set of quantization rules.
Definition quant.c:469
void Rast_get_range_min_max(const struct Range *, CELL *, CELL *)
Get range min and max.
size_t Rast_cell_size(RASTER_MAP_TYPE)
Returns size of a raster cell in bytes.
Definition alloc_cell.c:37
int Rast_read_range(const char *, const char *, struct Range *)
Read raster range (CELL)
void Rast_quant_get_ith_rule(const struct Quant *, int, DCELL *, DCELL *, CELL *, CELL *)
Returns the i'th quantization rule.
Definition quant.c:327
int Rast_map_is_fp(const char *, const char *)
Check if raster map is floating-point.
void Rast_quant_init(struct Quant *)
Initialize the structure.
Definition quant.c:175
#define Rast_is_d_null_value(dcellVal)
#define Rast_is_c_null_value(cellVal)
DCELL Rast_get_d_value(const void *, RASTER_MAP_TYPE)
Retrieves the value of given type from pointer p (DCELL)
int Rast_quant_nof_rules(const struct Quant *)
Returns the number of quantization rules defined.
Definition quant.c:309
#define min(x, y)
Definition draw2.c:29
#define max(x, y)
Definition draw2.c:30
float FCELL
Definition gis.h:636
double DCELL
Definition gis.h:635
int CELL
Definition gis.h:634
#define _(str)
Definition glocale.h:10
struct field_info * ff
int count
const char * name
Definition named_colr.c:6
double b
Definition r_raster.c:39
double l
Definition r_raster.c:39
void Rast_set_cats_fmt(const char *fmt, double m1, double a1, double m2, double a2, struct Categories *pcats)
Set category fmt (?)
int Rast_number_of_cats(struct Categories *pcats)
Get number of raster categories.
char * Rast_get_next_marked_d_cat(struct Categories *pcats, DCELL *rast1, DCELL *rast2, long *count)
Get next marked raster categories (DCELL)
char * Rast_get_next_marked_c_cat(struct Categories *pcats, CELL *rast1, CELL *rast2, long *count)
Get next marked raster categories (CELL)
void Rast_free_cats(struct Categories *pcats)
Free category structure memory.
char * Rast_get_next_marked_cat(struct Categories *pcats, void *rast1, void *rast2, long *count, RASTER_MAP_TYPE data_type)
Get next marked raster categories.
void Rast_rewind_cats(struct Categories *pcats)
Rewind raster categories.
void Rast_write_cats(const char *name, struct Categories *cats)
Write raster category file.
CELL Rast_get_max_c_cat(const char *name, const char *mapset)
Get the max category number.
int Rast_set_c_cat(const CELL *rast1, const CELL *rast2, const char *label, struct Categories *pcats)
Set a raster category label (CELL)
int Rast_set_d_cat(const DCELL *rast1, const DCELL *rast2, const char *label, struct Categories *pcats)
Set a raster category label (DCELL)
int Rast_read_vector_cats(const char *name, const char *mapset, struct Categories *pcats)
Read vector category file.
char * Rast_get_ith_d_cat(const struct Categories *pcats, int i, DCELL *rast1, DCELL *rast2)
Get category description (DCELL)
int Rast_sort_cats(struct Categories *pcats)
Sort categories.
char * Rast_get_f_cat(FCELL *rast, struct Categories *pcats)
Get a raster category label (FCELL)
int Rast_mark_cats(const void *rast_row, int ncols, struct Categories *pcats, RASTER_MAP_TYPE data_type)
Looks up the category label for each raster value (DCELL).
char * Rast_get_ith_cat(const struct Categories *pcats, int i, void *rast1, void *rast2, RASTER_MAP_TYPE data_type)
Get category description.
char * Rast_get_next_marked_f_cat(struct Categories *pcats, FCELL *rast1, FCELL *rast2, long *count)
Get next marked raster categories (FCELL)
int Rast_set_cat(const void *rast1, const void *rast2, const char *label, struct Categories *pcats, RASTER_MAP_TYPE data_type)
Set a raster category label.
char * Rast_get_cat(void *rast, struct Categories *pcats, RASTER_MAP_TYPE data_type)
Get a raster category label.
int Rast_set_f_cat(const FCELL *rast1, const FCELL *rast2, const char *label, struct Categories *pcats)
Set a raster category label (FCELL)
char * Rast_get_cats_title(const struct Categories *pcats)
Get title from category structure struct.
void Rast_copy_cats(struct Categories *pcats_to, const struct Categories *pcats_from)
Copy raster categories.
char * Rast_get_ith_c_cat(const struct Categories *pcats, int i, void *rast1, void *rast2)
Get category description (CELL)
void Rast_mark_d_cats(const DCELL *rast_row, int ncols, struct Categories *pcats)
Looks up the category label for each raster value (DCELL).
void Rast_unmark_cats(struct Categories *pcats)
Sets marks for all categories to 0.
int Rast_read_cats(const char *name, const char *mapset, struct Categories *pcats)
Read raster category file.
char * Rast_get_d_cat(DCELL *rast, struct Categories *pcats)
Get a raster category label (DCELL)
void Rast_write_vector_cats(const char *name, struct Categories *cats)
Write vector category file.
void Rast_mark_c_cats(const CELL *rast_row, int ncols, struct Categories *pcats)
Looks up the category label for each raster value (CELL).
void Rast_init_cats(const char *title, struct Categories *pcats)
Initialize category structure.
void Rast_set_cats_title(const char *title, struct Categories *pcats)
Set title in category structure.
char * Rast_get_c_cat(CELL *rast, struct Categories *pcats)
Get a raster category label (CELL)
void Rast_mark_f_cats(const FCELL *rast_row, int ncols, struct Categories *pcats)
Looks up the category label for each raster value (FCELL).
char * Rast_get_ith_f_cat(const struct Categories *pcats, int i, void *rast1, void *rast2)
Get category description (FCELL)
#define FCELL_TYPE
Definition raster.h:12
#define DCELL_TYPE
Definition raster.h:13
#define CELL_TYPE
Definition raster.h:11
int RASTER_MAP_TYPE
Definition raster.h:25
float a2
Definition raster.h:131
float m2
Definition raster.h:130
CELL num
Definition raster.h:123
char * fmt
Definition raster.h:127
float m1
Definition raster.h:128
char * title
Definition raster.h:126
float a1
Definition raster.h:129
struct Quant q
Definition raster.h:132