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