2
* \file lib/raster/cats.c
4
* \brief Raster Library - Raster categories management
6
* Code in this file works with category files. There are two formats:
7
* Pre 3.0 direct category encoding form:
11
* Elevation: 1000.00 to 1005.00 feet
12
* Elevation: 1005.00 to 1010.00 feet
13
* Elevation: 1010.00 to 1015.00 feet
19
* Elevation: $1.2 to $2.2 feet ## Format Statement
20
* 5.0 1000 5.0 1005 ## Coefficients
22
* The coefficient line can be followed by explicit category labels
23
* which override the format label generation.
26
* 5: . ## explicit category labels
28
* explicit labels can be also of the form:
29
* 5.5:5:9 label description
31
* 15:30 label description
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)
37
* $1.2 will print $1 with 2 decimal places.
39
* Also, the form $?xxx$yyy$ translates into yyy if the category is 1, xxx
40
* otherwise. The $yyy$ is optional. Thus
44
* will become: 1 meter (for category 1)
45
* 2 meters (for category 2), etc.
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":
51
* sprintf(buff,"Elevation: %.2f to %.2f feet", num*5.0+1000, num*5.0*1005)
53
* Note: while both the format and coefficent lins must be present
54
* a blank line for the fmt will effectively suppress automatic
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
63
* (C) 2001-2009 by the GRASS Development Team
65
* This program is free software under the GNU General Public License
66
* (>=v2). Read the file COPYING that comes with GRASS for details.
68
* \author Original author CERL
74
#include <grass/gis.h>
75
#include <grass/raster.h>
76
#include <grass/glocale.h>
78
static void get_cond(char **, char *, DCELL);
79
static int get_fmt(char **, char *, int *);
80
static int cmp(const void *, const void *);
82
static void write_cats(const char *element, const char *name,
83
struct Categories *cats);
84
static CELL read_cats(const char *element, const char *name,
85
const char *mapset, struct Categories *pcats, int full);
87
static struct Categories save_cats;
90
* \brief Read raster category file
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.
97
* \param name raster map name
98
* \param mapset mapset name
99
* \param[out] pcats pointer to Cats structure
101
* \return -1 on error
102
* \return 0 on success
104
int Rast_read_cats(const char *name,
105
const char *mapset, struct Categories *pcats)
107
switch (read_cats("cats", name, mapset, pcats, 1)) {
109
G_warning(_("Category support for <%s@%s> missing"), name, mapset);
112
G_warning(_("Category support for <%s@%s> invalid"), name, mapset);
122
* \brief Read vector category file
124
* <b>Note:</b> This function works with <b>old</b> vector format.
126
* \todo: To be moved to the vector library
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.
133
* \param name vector map name
134
* \param mapset mapset name
135
* \param[out] pcats pointer to Cats structure
137
* \return -1 on error
138
* \return 0 on success
140
int Rast_read_vector_cats(const char *name,
141
const char *mapset, struct Categories *pcats)
143
switch (read_cats("dig_cats", name, mapset, pcats, 1)) {
145
G_warning(_("Category support for vector map <%s@%s> missing"),
149
G_warning(_("Category support for vector map <%s@%s> invalid"),
160
\brief Get the max category number
162
Return the max category number of a raster map
165
\param name raster map name
166
\param mapset mapset name
169
\return number of cats
171
CELL Rast_get_max_c_cat(const char *name, const char *mapset)
176
/* return the max category number */
177
if (Rast_read_range(name, mapset, &range) < 0)
179
Rast_get_range_min_max(&range, &min, &max);
180
if (Rast_is_c_null_value(&max))
185
static CELL read_cats(const char *element,
187
const char *mapset, struct Categories *pcats, int full)
197
if (strncmp(element, "dig", 3) == 0)
200
fp_map = Rast_map_is_fp(name, mapset);
202
if (!(fd = G_fopen_old(element, name, mapset)))
205
/* Read the number of categories */
206
if (G_getl(buff, sizeof buff, fd) == 0)
209
if (sscanf(buff, "# %ld", &num) == 1)
211
else if (sscanf(buff, "%ld", &num) == 1)
217
return 0; /* coorect */
221
/* Read the title for the file */
222
if (G_getl(buff, sizeof buff, fd) == 0)
225
/* G_ascii_check(buff) ; */
227
Rast_init_cats(buff, pcats);
233
float m1, a1, m2, a2;
235
if (G_getl(fmt, sizeof fmt, fd) == 0)
237
/* next line contains equation coefficients */
238
if (G_getl(buff, sizeof buff, fd) == 0)
240
if (sscanf(buff, "%f %f %f %f", &m1, &a1, &m2, &a2) != 4)
242
Rast_set_cats_fmt(fmt, m1, a1, m2, a2, pcats);
245
/* Read all category names */
246
for (cat = 0;; cat++) {
249
if (G_getl(buff, sizeof buff, fd) == 0)
252
Rast_set_c_cat(&cat, &cat, buff, pcats);
255
if (sscanf(buff, "%1s", label) != 1)
260
/* for fp maps try to read a range of data */
262
&& sscanf(buff, "%lf:%lf:%[^\n]", &val1, &val2, label) == 3)
263
Rast_set_cat(&val1, &val2, label, pcats, DCELL_TYPE);
264
else if (sscanf(buff, "%d:%[^\n]", &cat, label) >= 1)
265
Rast_set_cat(&cat, &cat, label, pcats, CELL_TYPE);
266
else if (sscanf(buff, "%lf:%[^\n]", &val1, label) >= 1)
267
Rast_set_cat(&val1, &val1, label, pcats, DCELL_TYPE);
281
* \brief Get title from category structure struct
283
* \todo Remove from GIS Library, replace by Rast_get_c_cats_title().
285
* Map layers store a one-line title in the category structure as
286
* well. This routine returns a pointer to the title contained in the
287
* <i>cats</i> structure. A legal pointer is always returned. If the
288
* map layer does not have a title, then a pointer to the empty string
291
* \param pcats pointer to Categories structure
294
* \return "" if missing
296
char *Rast_get_cats_title(const struct Categories *pcats)
298
return pcats->title ? pcats->title : "";
302
* \brief Get a raster category label (CELL)
304
* This routine looks up category <i>rast</i> in the <i>pcats</i>
305
* structure and returns a pointer to a string which is the label for
306
* the category. A legal pointer is always returned. If the category
307
* does not exist in <i>pcats</i>, then a pointer to the empty string
310
* <b>Warning:</b> The pointer that is returned points to a hidden
311
* static buffer. Successive calls to Rast_get_c_cat() overwrite this
314
* \param rast cell value
315
* \param pcats pointer to Categories structure
317
* \return pointer to category label
318
* \return "" if category is not found
320
char *Rast_get_c_cat(CELL * rast, struct Categories *pcats)
322
return Rast_get_cat(rast, pcats, CELL_TYPE);
326
* \brief Get a raster category label (FCELL)
328
* This routine looks up category <i>rast</i> in the <i>pcats</i>
329
* structure and returns a pointer to a string which is the label for
330
* the category. A legal pointer is always returned. If the category
331
* does not exist in <i>pcats</i>, then a pointer to the empty string
334
* <b>Warning:</b> The pointer that is returned points to a hidden
335
* static buffer. Successive calls to Rast_get_c_cat() overwrite this
338
* \param rast cell value
339
* \param pcats pointer to Categories structure
341
* \return pointer to category label
342
* \return "" if category is not found
344
char *Rast_get_f_cat(FCELL * rast, struct Categories *pcats)
346
return Rast_get_cat(rast, pcats, FCELL_TYPE);
350
* \brief Get a raster category label (DCELL)
352
* This routine looks up category <i>rast</i> in the <i>pcats</i>
353
* structure and returns a pointer to a string which is the label for
354
* the category. A legal pointer is always returned. If the category
355
* does not exist in <i>pcats</i>, then a pointer to the empty string
358
* <b>Warning:</b> The pointer that is returned points to a hidden
359
* static buffer. Successive calls to Rast_get_c_cat() overwrite this
362
* \param rast cell value
363
* \param pcats pointer to Categories structure
365
* \return pointer to category label
366
* \return "" if category is not found
368
char *Rast_get_d_cat(DCELL * rast, struct Categories *pcats)
370
return Rast_get_cat(rast, pcats, DCELL_TYPE);
374
* \brief Get a raster category label
376
* This routine looks up category <i>rast</i> in the <i>pcats</i>
377
* structure and returns a pointer to a string which is the label for
378
* the category. A legal pointer is always returned. If the category
379
* does not exist in <i>pcats</i>, then a pointer to the empty string
382
* <b>Warning:</b> The pointer that is returned points to a hidden
383
* static buffer. Successive calls to Rast_get_c_cat() overwrite this
386
* \param rast cell value
387
* \param pcats pointer to Categories structure
388
* \param data_type map type (CELL, FCELL, DCELL)
390
* \return pointer to category label
391
* \return "" if category is not found
393
char *Rast_get_cat(void *rast,
394
struct Categories *pcats, RASTER_MAP_TYPE data_type)
396
static char label[1024];
401
char fmt[30], value_str[30];
403
if (Rast_is_null_value(rast, data_type)) {
404
sprintf(label, "no data");
408
/* first search the list of labels */
410
val = Rast_get_d_value(rast, data_type);
411
i = Rast_quant_get_cell_value(&pcats->q, val);
413
G_debug(5, "Rast_get_cat(): val %lf found i %d", val, i);
415
if (!Rast_is_c_null_value(&i) && i < pcats->ncats) {
416
if (pcats->labels[i] != NULL)
417
return pcats->labels[i];
421
/* generate the label */
422
if ((f = pcats->fmt) == NULL)
425
a[0] = (float)val *pcats->m1 + pcats->a1;
426
a[1] = (float)val *pcats->m2 + pcats->a2;
434
else if (*f == '?') {
436
get_cond(&f, v = value_str, val);
440
else if (get_fmt(&f, fmt, &i)) {
441
sprintf(v = value_str, fmt, a[i]);
457
* \brief Sets marks for all categories to 0.
459
* This initializes Categories structure for subsequest calls to
460
* Rast_mark_cats() for each row of data, where non-zero mark for
461
* i-th label means that some of the cells in rast_row are labeled
462
* with i-th label and fall into i-th data range. These marks help
463
* determine from the Categories structure which labels were used and
466
* \param pcats pointer to Categories structure
468
void Rast_unmark_cats(struct Categories *pcats)
472
for (i = 0; i < pcats->ncats; i++)
477
* \brief Looks up the category label for each raster value (CELL).
479
* Looks up the category label for each raster value in the
480
* <i>rast_row</i> and updates the marks for labels found.
482
* <b>Note:</b> Non-zero mark for i-th label stores the number of of
483
* raster cells read so far which are labeled with i-th label and fall
484
* into i-th data range.
486
* \param rast_row raster row to update stats
487
* \param ncols number of columns
488
* \param pcats pointer to Categories structure
491
void Rast_mark_c_cats(const CELL * rast_row,
492
int ncols, struct Categories *pcats)
494
Rast_mark_cats(rast_row, ncols, pcats, CELL_TYPE);
498
* \brief Looks up the category label for each raster value (FCELL).
500
* Looks up the category label for each raster value in the
501
* <i>rast_row</i> and updates the marks for labels found.
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.
507
* \param rast_row raster row to update stats
508
* \param ncols number of columns
509
* \param pcats pointer to Categories structure
512
void Rast_mark_f_cats(const FCELL * rast_row,
513
int ncols, struct Categories *pcats)
515
Rast_mark_cats(rast_row, ncols, pcats, FCELL_TYPE);
519
* \brief Looks up the category label for each raster value (DCELL).
521
* Looks up the category label for each raster value in the
522
* <i>rast_row</i> and updates the marks for labels found.
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.
528
* \param rast_row raster row to update stats
529
* \param ncols number of columns
530
* \param pcats pointer to Categories structure
533
void Rast_mark_d_cats(const DCELL * rast_row,
534
int ncols, struct Categories *pcats)
536
Rast_mark_cats(rast_row, ncols, pcats, DCELL_TYPE);
540
* \brief Looks up the category label for each raster value (DCELL).
542
* Looks up the category label for each raster value in the
543
* <i>rast_row</i> and updates the marks for labels found.
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.
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
554
* \return -1 on error
555
* \return 1 on success
557
int Rast_mark_cats(const void *rast_row,
558
int ncols, struct Categories *pcats,
559
RASTER_MAP_TYPE data_type)
561
size_t size = Rast_cell_size(data_type);
564
while (ncols-- > 0) {
565
i = Rast_quant_get_cell_value(&pcats->q,
566
Rast_get_d_value(rast_row, data_type));
567
if (Rast_is_c_null_value(&i))
569
if (i > pcats->ncats)
572
rast_row = G_incr_void_ptr(rast_row, size);
578
* \brief Rewind raster categories
580
* After call to this function Rast_get_next_marked_cat() returns
581
* the first marked cat label.
583
* \param pcats pointer to Categories structure
585
void Rast_rewind_cats(struct Categories *pcats)
587
pcats->last_marked_rule = -1;
591
\brief Get next marked raster categories (DCELL)
593
\param pcats pointer to Categories structure
594
\param rast1, rast2 cell values (raster range)
595
\param[out] count count
597
\return NULL if not found
598
\return description if found
600
char *Rast_get_next_marked_d_cat(struct Categories *pcats,
601
DCELL * rast1, DCELL * rast2, long *count)
607
/* pcats->ncats should be == Rast_quant_nof_rules(&pcats->q) */
609
G_debug(3, "last marked %d nrules %d\n", pcats->last_marked_rule,
610
Rast_quant_nof_rules(&pcats->q));
612
for (i = pcats->last_marked_rule + 1; i < Rast_quant_nof_rules(&pcats->q);
614
descr = Rast_get_ith_d_cat(pcats, i, rast1, rast2);
615
G_debug(5, "%d %d", i, pcats->marks[i]);
616
if (pcats->marks[i]) {
625
*count = pcats->marks[i];
626
pcats->last_marked_rule = i;
631
\brief Get next marked raster categories (CELL)
633
\param pcats pointer to Categories structure
634
\param rast1, rast2 cell values (raster range)
635
\param[out] count count
637
\return NULL if not found
638
\return description if found
640
char *Rast_get_next_marked_c_cat(struct Categories *pcats,
641
CELL * rast1, CELL * rast2, long *count)
643
return Rast_get_next_marked_cat(pcats, rast1, rast2, count, CELL_TYPE);
647
\brief Get next marked raster categories (FCELL)
649
\param pcats pointer to Categories structure
650
\param rast1, rast2 cell values (raster range)
651
\param[out] count count
653
\return NULL if not found
654
\return description if found
656
char *Rast_get_next_marked_f_cat(struct Categories *pcats,
657
FCELL * rast1, FCELL * rast2, long *count)
659
return Rast_get_next_marked_cat(pcats, rast1, rast2, count, FCELL_TYPE);
663
\brief Get next marked raster categories
665
\param pcats pointer to Categories structure
666
\param rast1, rast2 cell values (raster range)
667
\param[out] count count
668
\param data_type map type
670
\return NULL if not found
671
\return description if found
673
char *Rast_get_next_marked_cat(struct Categories *pcats,
674
void *rast1, void *rast2,
675
long *count, RASTER_MAP_TYPE data_type)
680
lab = Rast_get_next_marked_d_cat(pcats, &val1, &val2, count);
681
Rast_set_d_value(rast1, val1, data_type);
682
Rast_set_d_value(rast2, val2, data_type);
686
static int get_fmt(char **f, char *fmt, int *i)
717
while (*ff >= '0' && *ff <= '9')
725
static void get_cond(char **f, char *value, DCELL val)
754
* \brief Set a raster category label (CELL)
756
* Adds the label for range <i>rast1</i> through <i>rast2</i> in
757
* category structure <i>pcats</i>.
759
* \param rast1, rast2 raster values (range)
760
* \param label category label
761
* \param pcats pointer to Categories structure
763
* \return -1 on error
764
* \return 0 if null value detected
765
* \return 1 on success
767
int Rast_set_c_cat(const CELL * rast1, const CELL * rast2,
768
const char *label, struct Categories *pcats)
770
return Rast_set_cat(rast1, rast2, label, pcats, CELL_TYPE);
774
* \brief Set a raster category label (FCELL)
776
* Adds the label for range <i>rast1</i> through <i>rast2</i> in
777
* category structure <i>pcats</i>.
779
* \param rast1, rast2 raster values (range)
780
* \param label category label
781
* \param pcats pointer to Categories structure
785
int Rast_set_f_cat(const FCELL * rast1, const FCELL * rast2,
786
const char *label, struct Categories *pcats)
788
return Rast_set_cat(rast1, rast2, label, pcats, FCELL_TYPE);
792
* \brief Set a raster category label (DCELL)
794
* Adds the label for range <i>rast1</i> through <i>rast2</i> in
795
* category structure <i>pcats</i>.
797
* \param rast1, rast2 raster values (range)
798
* \param label category label
799
* \param pcats pointer to Categories structure
801
* \return -1 on error
802
* \return 0 if null value detected
803
* \return 1 on success
805
int Rast_set_d_cat(const DCELL * rast1, const DCELL * rast2,
806
const char *label, struct Categories *pcats)
813
/* DEBUG fprintf(stderr,"Rast_set_d_cat(rast1 = %p,rast2 = %p,label = '%s',pcats = %p)\n",
814
rast1,rast2,label,pcats); */
815
if (Rast_is_d_null_value(rast1))
817
if (Rast_is_d_null_value(rast2))
819
/* DEBUG fprintf (stderr, "Rast_set_d_cat(): adding quant rule: %f %f %d %d\n", *rast1, *rast2, pcats->ncats, pcats->ncats); */
820
/* the set_cat() functions are used in many places to reset the labels
821
for the range (or cat) with existing label. In this case we don't
822
want to store both rules with identical range even though the result
823
of get_cat() will be correct, since it will use rule added later.
824
we don't want to overuse memory and we don't want rules which are
825
not used to be writen out in cats file. So we first look if
826
the label for this range has been sen, and if it has, overwrite it */
828
for (i = 0; i < pcats->ncats; i++) {
829
descr = Rast_get_ith_d_cat(pcats, i, &dtmp1, &dtmp2);
830
if ((dtmp1 == *rast1 && dtmp2 == *rast2)
831
|| (dtmp1 == *rast2 && dtmp2 == *rast1)) {
832
if (pcats->labels[i] != NULL)
833
G_free(pcats->labels[i]);
834
pcats->labels[i] = G_store(label);
835
G_newlines_to_spaces(pcats->labels[i]);
836
G_strip(pcats->labels[i]);
840
/* when rule for this range does not exist */
841
/* DEBUG fprintf (stderr, "Rast_set_d_cat(): New rule: adding %d %p\n", i, pcats->labels); */
842
Rast_quant_add_rule(&pcats->q, *rast1, *rast2, pcats->ncats,
845
if (pcats->nalloc < pcats->ncats) {
846
/* DEBUG fprintf (stderr, "Rast_set_d_cat(): need more space nalloc = %d ncats = %d\n", pcats->nalloc,pcats->ncats); */
847
len = (pcats->nalloc + 256) * sizeof(char *);
848
/* DEBUG fprintf (stderr, "Rast_set_d_cat(): allocating %d labels(%d)\n", pcats->nalloc + 256,(int)len); */
849
if (len != (int)len) { /* make sure len doesn't overflow int */
853
/* DEBUG fprintf(stderr,"Rast_set_d_cat(): pcats->nalloc = %d, pcats->labels = (%p), len = %d\n",pcats->nalloc,pcats->labels,(int)len); */
855
/* DEBUG fprintf(stderr,"Rast_set_d_cat(): Realloc-ing pcats->labels (%p)\n",pcats->labels); */
857
(char **)G_realloc((char *)pcats->labels, (int)len);
860
/* DEBUG fprintf(stderr,"Rast_set_d_cat(): alloc-ing new labels pointer array\n"); */
861
pcats->labels = (char **)G_malloc((int)len);
863
/* fflush(stderr); */
864
/* DEBUG fprintf (stderr, "Rast_set_d_cats(): allocating %d marks(%d)\n", pcats->nalloc + 256,(int)len); */
865
len = (pcats->nalloc + 256) * sizeof(int);
866
if (len != (int)len) { /* make sure len doesn't overflow int */
871
pcats->marks = (int *)G_realloc((char *)pcats->marks, (int)len);
873
pcats->marks = (int *)G_malloc((int)len);
874
pcats->nalloc += 256;
876
/* DEBUG fprintf(stderr,"Rast_set_d_cats(): store new label\n"); */
877
pcats->labels[pcats->ncats - 1] = G_store(label);
878
G_newlines_to_spaces(pcats->labels[pcats->ncats - 1]);
879
G_strip(pcats->labels[pcats->ncats - 1]);
881
fprintf (stderr, "%d %s\n", pcats->ncats - 1, pcats->labels[pcats->ncats - 1]);
883
/* updates cats.num = max cat values. This is really just used in old
884
raster programs, and I am doing it for backwards cmpatibility (Olga) */
885
if ((CELL) * rast1 > pcats->num)
886
pcats->num = (CELL) * rast1;
887
if ((CELL) * rast2 > pcats->num)
888
pcats->num = (CELL) * rast2;
889
/* DEBUG fprintf(stderr,"Rast_set_d_cat(): done\n"); */
890
/* DEBUG fflush(stderr); */
896
* \brief Set a raster category label
898
* Adds the label for range <i>rast1</i> through <i>rast2</i> in
899
* category structure <i>pcats</i>.
901
* \param rast1, rast2 raster values (range)
902
* \param label category label
903
* \param pcats pointer to Categories structure
904
* \param data_type map type
906
* \return -1 on error
907
* \return 0 if null value detected
908
* \return 1 on success
911
int Rast_set_cat(const void *rast1, const void *rast2,
913
struct Categories *pcats, RASTER_MAP_TYPE data_type)
917
val1 = Rast_get_d_value(rast1, data_type);
918
val2 = Rast_get_d_value(rast2, data_type);
919
return Rast_set_d_cat(&val1, &val2, label, pcats);
923
* \brief Write raster category file
925
* \todo To be removed, replaced by Rast_write_cats().
927
* Writes the category file for the raster map <i>name</i> in the
928
* current mapset from the <i>cats</i> structure.
930
* \param name map name
931
* \param cats pointer to Categories structure
935
void Rast_write_cats(const char *name, struct Categories *cats)
937
write_cats("cats", name, cats);
941
* \brief Write vector category file
943
* <b>Note:</b> Used for only old vector format!
945
* \todo Move to the vector library.
947
* \param name map name
948
* \param cats pointer to Categories structure
952
void Rast_write_vector_cats(const char *name, struct Categories *cats)
954
write_cats("dig_cats", name, cats);
957
static void write_cats(const char *element, const char *name,
958
struct Categories *cats)
964
char str1[100], str2[100];
966
fd = G_fopen_new(element, name);
968
G_fatal_error(_("Unable to open %s file for map <%s>"), element, name);
970
/* write # cats - note # indicate 3.0 or later */
971
fprintf(fd, "# %ld categories\n", (long)cats->num);
974
fprintf(fd, "%s\n", cats->title != NULL ? cats->title : "");
976
/* write format and coefficients */
977
fprintf(fd, "%s\n", cats->fmt != NULL ? cats->fmt : "");
978
fprintf(fd, "%.2f %.2f %.2f %.2f\n",
979
cats->m1, cats->a1, cats->m2, cats->a2);
981
/* if the map is integer or if this is a vector map, sort labels */
982
if (strncmp(element, "dig", 3) == 0)
985
fp_map = Rast_map_is_fp(name, G_mapset());
987
Rast_sort_cats(cats);
989
/* write the cat numbers:label */
990
for (i = 0; i < Rast_quant_nof_rules(&cats->q); i++) {
991
descr = Rast_get_ith_d_cat(cats, i, &val1, &val2);
992
if ((cats->fmt && cats->fmt[0])
993
|| (descr && descr[0])) {
995
sprintf(str1, "%.10f", val1);
996
G_trim_decimal(str1);
997
fprintf(fd, "%s:%s\n", str1, descr != NULL ? descr : "");
1000
sprintf(str1, "%.10f", val1);
1001
G_trim_decimal(str1);
1002
sprintf(str2, "%.10f", val2);
1003
G_trim_decimal(str2);
1004
fprintf(fd, "%s:%s:%s\n", str1, str2,
1005
descr != NULL ? descr : "");
1013
* \brief Get category description (DCELL)
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>.
1019
* \param pcats pointer to Categories structure
1021
* \param rast1, rast2 raster values (range)
1023
* \return "" on error
1024
* \return pointer to category description
1026
char *Rast_get_ith_d_cat(const struct Categories *pcats,
1027
int i, DCELL * rast1, DCELL * rast2)
1031
if (i > pcats->ncats) {
1032
Rast_set_d_null_value(rast1, 1);
1033
Rast_set_d_null_value(rast2, 1);
1036
Rast_quant_get_ith_rule(&pcats->q, i, rast1, rast2, &index, &index);
1037
return pcats->labels[index];
1041
* \brief Get category description (FCELL)
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>.
1047
* \param pcats pointer to Categories structure
1049
* \param rast1, rast2 raster values (range)
1051
* \return "" on error
1052
* \return pointer to category description
1054
char *Rast_get_ith_f_cat(const struct Categories *pcats,
1055
int i, void *rast1, void *rast2)
1057
RASTER_MAP_TYPE data_type = FCELL_TYPE;
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);
1068
* \brief Get category description (CELL)
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>.
1074
* \param pcats pointer to Categories structure
1076
* \param rast1, rast2 raster values (range)
1078
* \return "" on error
1079
* \return pointer to category description
1081
char *Rast_get_ith_c_cat(const struct Categories *pcats,
1082
int i, void *rast1, void *rast2)
1084
RASTER_MAP_TYPE data_type = CELL_TYPE;
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);
1095
* \brief Get category description
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>.
1101
* \param pcats pointer to Categories structure
1103
* \param rast1, rast2 raster values (range)
1104
* \param data_type map type
1106
* \return "" on error
1107
* \return pointer to category description
1109
char *Rast_get_ith_cat(const struct Categories *pcats, int i, void *rast1,
1110
void *rast2, RASTER_MAP_TYPE data_type)
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);
1122
* \brief Initialize category structure
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>.
1131
struct Categories cats;
1132
Rast_init_cats ("", &cats);
1135
* \todo Eliminate pcats->num. Num has no meaning in new Categories
1136
* structure and only stores (int) largets data value for backwards
1139
* \param title title
1140
* \param pcats pointer to Categories structure
1142
void Rast_init_cats(const char *title, struct Categories *pcats)
1144
Rast_set_cats_title(title, pcats);
1145
pcats->labels = NULL;
1154
pcats->last_marked_rule = -1;
1155
Rast_quant_init(&pcats->q);
1159
* \brief Set title in category structure
1161
* \todo To be removed, replaced by Rast_set_cats_title().
1163
* The <i>title</i> is copied into the <i>pcats</i> structure.
1165
* \param title title
1166
* \param pcats pointer to Categories structure
1168
void Rast_set_cats_title(const char *title, struct Categories *pcats)
1172
pcats->title = G_store(title);
1173
G_newlines_to_spaces(pcats->title);
1174
G_strip(pcats->title);
1178
\brief Set category fmt (?)
1185
\param pcats pointer to Categories structure
1187
void Rast_set_cats_fmt(const char *fmt, double m1, double a1, double m2,
1188
double a2, struct Categories *pcats)
1195
pcats->fmt = G_store(fmt);
1196
G_newlines_to_spaces(pcats->fmt);
1197
G_strip(pcats->fmt);
1201
* \brief Free category structure memory
1203
* \todo To be removed, replaced by Rast_free_cats().
1205
* Frees memory allocated by Rast_read_cats(), Rast_init_cats() and
1208
* \param pcats pointer to Categories structure
1210
void Rast_free_cats(struct Categories *pcats)
1214
if (pcats->title != NULL) {
1215
G_free(pcats->title);
1216
pcats->title = NULL;
1218
if (pcats->fmt != NULL) {
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;
1230
Rast_quant_free(&pcats->q);
1236
* \brief Copy raster categories
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.
1242
* \param pcats_to pointer to destination Categories structure
1243
* \param pcats_from pointer to source Categories structure
1245
void Rast_copy_cats(struct Categories *pcats_to,
1246
const struct Categories *pcats_from)
1252
Rast_init_cats(pcats_from->title, pcats_to);
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);
1260
\brief Get number of raster categories
1262
\param pcats pointer to Categories structure
1264
\return number of categories
1266
int Rast_number_of_cats(struct Categories *pcats)
1268
return pcats->ncats;
1272
\brief Sort categories
1274
\param pcats pointer to Categories structure
1276
\return -1 on error (nothing to sort)
1277
\return 0 on success
1279
int Rast_sort_cats(struct Categories *pcats)
1281
int *indexes, i, ncats;
1285
if (pcats->ncats <= 1)
1288
ncats = pcats->ncats;
1289
G_debug(3, "Rast_sort_cats(): Copying to save cats buffer");
1290
Rast_copy_cats(&save_cats, pcats);
1291
Rast_free_cats(pcats);
1293
indexes = (int *)G_malloc(sizeof(int) * ncats);
1294
for (i = 0; i < ncats; i++)
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
pcats, pcats->labels);
1303
Rast_set_d_cat(&d1, &d2, descr, pcats);
1305
Rast_free_cats(&save_cats);
1310
static int cmp(const void *aa, const void *bb)
1312
const int *a = aa, *b = bb;
1313
DCELL min_rast1, min_rast2, max_rast1, max_rast2;
1316
Rast_quant_get_ith_rule(&(save_cats.q), *a,
1317
&min_rast1, &max_rast1, &index, &index);
1318
Rast_quant_get_ith_rule(&(save_cats.q), *b,
1319
&min_rast2, &max_rast2, &index, &index);
1320
if (min_rast1 < min_rast2)
1322
if (min_rast1 > min_rast2)