~ubuntu-branches/ubuntu/vivid/grass/vivid-proposed

« back to all changes in this revision

Viewing changes to lib/raster/cats.c

  • Committer: Package Import Robot
  • Author(s): Bas Couwenberg
  • Date: 2015-02-20 23:12:08 UTC
  • mfrom: (8.2.6 experimental)
  • Revision ID: package-import@ubuntu.com-20150220231208-1u6qvqm84v430b10
Tags: 7.0.0-1~exp1
* New upstream release.
* Update python-ctypes-ternary.patch to use if/else instead of and/or.
* Drop check4dev patch, rely on upstream check.
* Add build dependency on libpq-dev to grass-dev for libpq-fe.h.
* Drop patches applied upstream, refresh remaining patches.
* Update symlinks for images switched from jpg to png.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 coefficent lins 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
 
 
78
static void get_cond(char **, char *, DCELL);
 
79
static int get_fmt(char **, char *, int *);
 
80
static int cmp(const void *, const void *);
 
81
 
 
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);
 
86
 
 
87
static 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
 */
 
104
int Rast_read_cats(const char *name,
 
105
                   const char *mapset, 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
 */
 
140
int Rast_read_vector_cats(const char *name,
 
141
                          const char *mapset, 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"),
 
146
                  name, mapset);
 
147
        break;
 
148
    case -1:
 
149
        G_warning(_("Category support for vector map <%s@%s> invalid"),
 
150
                  name, 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
 */
 
171
CELL 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);
 
180
    if (Rast_is_c_null_value(&max))
 
181
        max = 0;
 
182
    return max;
 
183
}
 
184
 
 
185
static CELL read_cats(const char *element,
 
186
                      const char *name,
 
187
                      const char *mapset, struct Categories *pcats, int full)
 
188
{
 
189
    FILE *fd;
 
190
    char buff[1024];
 
191
    CELL cat;
 
192
    DCELL val1, val2;
 
193
    int old = 0, fp_map;
 
194
    long num = -1;
 
195
 
 
196
 
 
197
    if (strncmp(element, "dig", 3) == 0)
 
198
        fp_map = 0;
 
199
    else
 
200
        fp_map = Rast_map_is_fp(name, mapset);
 
201
 
 
202
    if (!(fd = G_fopen_old(element, name, mapset)))
 
203
        return -2;
 
204
 
 
205
    /* Read the number of categories */
 
206
    if (G_getl(buff, sizeof buff, fd) == 0)
 
207
        goto error;
 
208
 
 
209
    if (sscanf(buff, "# %ld", &num) == 1)
 
210
        old = 0;
 
211
    else if (sscanf(buff, "%ld", &num) == 1)
 
212
        old = 1;
 
213
 
 
214
    if (!full) {
 
215
        fclose(fd);
 
216
        if (num < 0)
 
217
            return 0;           /* coorect */
 
218
        return (CELL) num;
 
219
    }
 
220
 
 
221
    /* Read the title for the file */
 
222
    if (G_getl(buff, sizeof buff, fd) == 0)
 
223
        goto error;
 
224
    G_strip(buff);
 
225
    /*    G_ascii_check(buff) ; */
 
226
 
 
227
    Rast_init_cats(buff, pcats);
 
228
    if (num >= 0)
 
229
        pcats->num = num;
 
230
 
 
231
    if (!old) {
 
232
        char fmt[256];
 
233
        float m1, a1, m2, a2;
 
234
 
 
235
        if (G_getl(fmt, sizeof fmt, fd) == 0)
 
236
            goto error;
 
237
        /* next line contains equation coefficients */
 
238
        if (G_getl(buff, sizeof buff, fd) == 0)
 
239
            goto error;
 
240
        if (sscanf(buff, "%f %f %f %f", &m1, &a1, &m2, &a2) != 4)
 
241
            goto error;
 
242
        Rast_set_cats_fmt(fmt, m1, a1, m2, a2, pcats);
 
243
    }
 
244
 
 
245
    /* Read all category names */
 
246
    for (cat = 0;; cat++) {
 
247
        char label[1024];
 
248
 
 
249
        if (G_getl(buff, sizeof buff, fd) == 0)
 
250
            break;
 
251
        if (old)
 
252
            Rast_set_c_cat(&cat, &cat, buff, pcats);
 
253
        else {
 
254
            *label = 0;
 
255
            if (sscanf(buff, "%1s", label) != 1)
 
256
                continue;
 
257
            if (*label == '#')
 
258
                continue;
 
259
            *label = 0;
 
260
            /* for fp maps try to read a range of data */
 
261
            if (fp_map
 
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);
 
268
            else
 
269
                goto error;
 
270
        }
 
271
    }
 
272
 
 
273
    fclose(fd);
 
274
    return 0;
 
275
  error:
 
276
    fclose(fd);
 
277
    return -1;
 
278
}
 
279
 
 
280
/*!
 
281
 * \brief Get title from category structure struct
 
282
 *
 
283
 * \todo Remove from GIS Library, replace by Rast_get_c_cats_title().
 
284
 *
 
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
 
289
 * "" is returned.
 
290
 *
 
291
 * \param pcats pointer to Categories structure
 
292
 *
 
293
 * \return title
 
294
 * \return "" if missing
 
295
 */
 
296
char *Rast_get_cats_title(const struct Categories *pcats)
 
297
{
 
298
    return pcats->title ? pcats->title : "";
 
299
}
 
300
 
 
301
/*!
 
302
 * \brief Get a raster category label (CELL)
 
303
 *
 
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
 
308
 * "" is returned.
 
309
 *
 
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
 
312
 * buffer.
 
313
 *
 
314
 * \param rast cell value
 
315
 * \param pcats pointer to Categories structure
 
316
 *
 
317
 * \return pointer to category label
 
318
 * \return "" if category is not found
 
319
 */
 
320
char *Rast_get_c_cat(CELL * rast, struct Categories *pcats)
 
321
{
 
322
    return Rast_get_cat(rast, pcats, CELL_TYPE);
 
323
}
 
324
 
 
325
/*!
 
326
 * \brief Get a raster category label (FCELL)
 
327
 *
 
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
 
332
 * "" is returned.
 
333
 *
 
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
 
336
 * buffer.
 
337
 *
 
338
 * \param rast cell value
 
339
 * \param pcats pointer to Categories structure
 
340
 *
 
341
 * \return pointer to category label
 
342
 * \return "" if category is not found
 
343
 */
 
344
char *Rast_get_f_cat(FCELL * rast, struct Categories *pcats)
 
345
{
 
346
    return Rast_get_cat(rast, pcats, FCELL_TYPE);
 
347
}
 
348
 
 
349
/*!
 
350
 * \brief Get a raster category label (DCELL)
 
351
 *
 
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
 
356
 * "" is returned.
 
357
 *
 
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
 
360
 * buffer.
 
361
 *
 
362
 * \param rast cell value
 
363
 * \param pcats pointer to Categories structure
 
364
 *
 
365
 * \return pointer to category label
 
366
 * \return "" if category is not found
 
367
 */
 
368
char *Rast_get_d_cat(DCELL * rast, struct Categories *pcats)
 
369
{
 
370
    return Rast_get_cat(rast, pcats, DCELL_TYPE);
 
371
}
 
372
 
 
373
/*!
 
374
 * \brief Get a raster category label
 
375
 *
 
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
 
380
 * "" is returned.
 
381
 *
 
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
 
384
 * buffer.
 
385
 *
 
386
 * \param rast cell value
 
387
 * \param pcats pointer to Categories structure
 
388
 * \param data_type map type (CELL, FCELL, DCELL)
 
389
 *
 
390
 * \return pointer to category label
 
391
 * \return "" if category is not found
 
392
 */
 
393
char *Rast_get_cat(void *rast,
 
394
                   struct Categories *pcats, RASTER_MAP_TYPE data_type)
 
395
{
 
396
    static char label[1024];
 
397
    char *f, *l, *v;
 
398
    CELL i;
 
399
    DCELL val;
 
400
    float a[2];
 
401
    char fmt[30], value_str[30];
 
402
 
 
403
    if (Rast_is_null_value(rast, data_type)) {
 
404
        sprintf(label, "no data");
 
405
        return label;
 
406
    }
 
407
 
 
408
    /* first search the list of labels */
 
409
    *label = 0;
 
410
    val = Rast_get_d_value(rast, data_type);
 
411
    i = Rast_quant_get_cell_value(&pcats->q, val);
 
412
 
 
413
    G_debug(5, "Rast_get_cat(): val %lf found i %d", val, i);
 
414
 
 
415
    if (!Rast_is_c_null_value(&i) && i < pcats->ncats) {
 
416
        if (pcats->labels[i] != NULL)
 
417
            return pcats->labels[i];
 
418
        return label;
 
419
    }
 
420
 
 
421
    /* generate the label */
 
422
    if ((f = pcats->fmt) == NULL)
 
423
        return label;
 
424
 
 
425
    a[0] = (float)val *pcats->m1 + pcats->a1;
 
426
    a[1] = (float)val *pcats->m2 + pcats->a2;
 
427
 
 
428
    l = label;
 
429
    while (*f) {
 
430
        if (*f == '$') {
 
431
            f++;
 
432
            if (*f == '$')
 
433
                *l++ = *f++;
 
434
            else if (*f == '?') {
 
435
                f++;
 
436
                get_cond(&f, v = value_str, val);
 
437
                while (*v)
 
438
                    *l++ = *v++;
 
439
            }
 
440
            else if (get_fmt(&f, fmt, &i)) {
 
441
                sprintf(v = value_str, fmt, a[i]);
 
442
                while (*v)
 
443
                    *l++ = *v++;
 
444
            }
 
445
            else
 
446
                *l++ = '$';
 
447
        }
 
448
        else {
 
449
            *l++ = *f++;
 
450
        }
 
451
    }
 
452
    *l = 0;
 
453
    return label;
 
454
}
 
455
 
 
456
/*!
 
457
 * \brief Sets marks for all categories to 0.
 
458
 *
 
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
 
464
 * which weren't.
 
465
 *
 
466
 * \param pcats pointer to Categories structure
 
467
 */
 
468
void Rast_unmark_cats(struct Categories *pcats)
 
469
{
 
470
    int i;
 
471
 
 
472
    for (i = 0; i < pcats->ncats; i++)
 
473
        pcats->marks[i] = 0;
 
474
}
 
475
 
 
476
/*!
 
477
 * \brief Looks up the category label for each raster value (CELL).
 
478
 * 
 
479
 * Looks up the category label for each raster value in the
 
480
 * <i>rast_row</i> and updates the marks for labels found.
 
481
 *
 
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.
 
485
 *
 
486
 * \param rast_row raster row to update stats
 
487
 * \param ncols number of columns
 
488
 * \param pcats pointer to Categories structure
 
489
 *
 
490
 */
 
491
void Rast_mark_c_cats(const CELL * rast_row,
 
492
                      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
 */
 
512
void Rast_mark_f_cats(const FCELL * rast_row,
 
513
                      int ncols, 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
 */
 
533
void Rast_mark_d_cats(const DCELL * rast_row,
 
534
                      int ncols, 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
 */
 
557
int Rast_mark_cats(const void *rast_row,
 
558
                   int ncols, struct Categories *pcats,
 
559
                   RASTER_MAP_TYPE data_type)
 
560
{
 
561
    size_t size = Rast_cell_size(data_type);
 
562
    CELL i;
 
563
 
 
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))
 
568
            continue;
 
569
        if (i > pcats->ncats)
 
570
            return -1;
 
571
        pcats->marks[i]++;
 
572
        rast_row = G_incr_void_ptr(rast_row, size);
 
573
    }
 
574
    return 1;
 
575
}
 
576
 
 
577
/*!
 
578
 * \brief Rewind raster categories
 
579
 *
 
580
 * After call to this function Rast_get_next_marked_cat() returns
 
581
 * the first marked cat label.
 
582
 *
 
583
 * \param pcats pointer to Categories structure
 
584
 */
 
585
void Rast_rewind_cats(struct Categories *pcats)
 
586
{
 
587
    pcats->last_marked_rule = -1;
 
588
}
 
589
 
 
590
/*!
 
591
   \brief Get next marked raster categories (DCELL)
 
592
 
 
593
   \param pcats pointer to Categories structure
 
594
   \param rast1, rast2 cell values (raster range)
 
595
   \param[out] count count
 
596
 
 
597
   \return NULL if not found
 
598
   \return description if found
 
599
 */
 
600
char *Rast_get_next_marked_d_cat(struct Categories *pcats,
 
601
                                 DCELL * rast1, DCELL * rast2, long *count)
 
602
{
 
603
    char *descr = NULL;
 
604
    int found, i;
 
605
 
 
606
    found = 0;
 
607
    /* pcats->ncats should be == Rast_quant_nof_rules(&pcats->q) */
 
608
 
 
609
    G_debug(3, "last marked %d nrules %d\n", pcats->last_marked_rule,
 
610
            Rast_quant_nof_rules(&pcats->q));
 
611
 
 
612
    for (i = pcats->last_marked_rule + 1; i < Rast_quant_nof_rules(&pcats->q);
 
613
         i++) {
 
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]) {
 
617
            found = 1;
 
618
            break;
 
619
        }
 
620
    }
 
621
 
 
622
    if (!found)
 
623
        return NULL;
 
624
 
 
625
    *count = pcats->marks[i];
 
626
    pcats->last_marked_rule = i;
 
627
    return descr;
 
628
}
 
629
 
 
630
/*!
 
631
   \brief Get next marked raster categories (CELL)
 
632
 
 
633
   \param pcats pointer to Categories structure
 
634
   \param rast1, rast2 cell values (raster range)
 
635
   \param[out] count count
 
636
 
 
637
   \return NULL if not found
 
638
   \return description if found
 
639
 */
 
640
char *Rast_get_next_marked_c_cat(struct Categories *pcats,
 
641
                                 CELL * rast1, CELL * rast2, long *count)
 
642
{
 
643
    return Rast_get_next_marked_cat(pcats, rast1, rast2, count, CELL_TYPE);
 
644
}
 
645
 
 
646
/*!
 
647
   \brief Get next marked raster categories (FCELL)
 
648
 
 
649
   \param pcats pointer to Categories structure
 
650
   \param rast1, rast2 cell values (raster range)
 
651
   \param[out] count count
 
652
 
 
653
   \return NULL if not found
 
654
   \return description if found
 
655
 */
 
656
char *Rast_get_next_marked_f_cat(struct Categories *pcats,
 
657
                                 FCELL * rast1, FCELL * rast2, long *count)
 
658
{
 
659
    return Rast_get_next_marked_cat(pcats, rast1, rast2, count, FCELL_TYPE);
 
660
}
 
661
 
 
662
/*!
 
663
   \brief Get next marked raster categories
 
664
 
 
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
 
669
 
 
670
   \return NULL if not found
 
671
   \return description if found
 
672
 */
 
673
char *Rast_get_next_marked_cat(struct Categories *pcats,
 
674
                               void *rast1, void *rast2,
 
675
                               long *count, RASTER_MAP_TYPE data_type)
 
676
{
 
677
    DCELL val1, val2;
 
678
    char *lab;
 
679
 
 
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);
 
683
    return lab;
 
684
}
 
685
 
 
686
static int get_fmt(char **f, char *fmt, int *i)
 
687
{
 
688
    char *ff;
 
689
 
 
690
    ff = *f;
 
691
    if (*ff == 0)
 
692
        return 0;
 
693
    if (*ff == '$') {
 
694
        *f = ff + 1;
 
695
        return 0;
 
696
    }
 
697
    switch (*ff++) {
 
698
    case '1':
 
699
        *i = 0;
 
700
        break;
 
701
    case '2':
 
702
        *i = 1;
 
703
        break;
 
704
    default:
 
705
        return 0;
 
706
    }
 
707
    *fmt++ = '%';
 
708
    *fmt++ = '.';
 
709
    if (*ff++ != '.') {
 
710
        *f = ff - 1;
 
711
        *fmt++ = '0';
 
712
        *fmt++ = 'f';
 
713
        *fmt = 0;
 
714
        return 1;
 
715
    }
 
716
    *fmt = '0';
 
717
    while (*ff >= '0' && *ff <= '9')
 
718
        *fmt++ = *ff++;
 
719
    *fmt++ = 'f';
 
720
    *fmt = 0;
 
721
    *f = ff;
 
722
    return 1;
 
723
}
 
724
 
 
725
static void get_cond(char **f, char *value, DCELL val)
 
726
{
 
727
    char *ff;
 
728
 
 
729
    ff = *f;
 
730
    if (val == 1.) {
 
731
        while (*ff)
 
732
            if (*ff++ == '$')
 
733
                break;
 
734
    }
 
735
 
 
736
    while (*ff)
 
737
        if (*ff == '$') {
 
738
            ff++;
 
739
            break;
 
740
        }
 
741
        else
 
742
            *value++ = *ff++;
 
743
 
 
744
    if (val != 1.) {
 
745
        while (*ff)
 
746
            if (*ff++ == '$')
 
747
                break;
 
748
    }
 
749
    *value = 0;
 
750
    *f = ff;
 
751
}
 
752
 
 
753
/*!
 
754
 * \brief Set a raster category label (CELL)
 
755
 *
 
756
 * Adds the label for range <i>rast1</i> through <i>rast2</i> in
 
757
 * category structure <i>pcats</i>.
 
758
 *
 
759
 * \param rast1, rast2 raster values (range)
 
760
 * \param label category label
 
761
 * \param pcats pointer to Categories structure
 
762
 *
 
763
 * \return -1 on error
 
764
 * \return 0 if null value detected
 
765
 * \return 1 on success
 
766
 */
 
767
int Rast_set_c_cat(const CELL * rast1, const CELL * rast2,
 
768
                   const char *label, struct Categories *pcats)
 
769
{
 
770
    return Rast_set_cat(rast1, rast2, label, pcats, CELL_TYPE);
 
771
}
 
772
 
 
773
/*!
 
774
 * \brief Set a raster category label (FCELL)
 
775
 *
 
776
 * Adds the label for range <i>rast1</i> through <i>rast2</i> in
 
777
 * category structure <i>pcats</i>.
 
778
 *
 
779
 * \param rast1, rast2 raster values (range)
 
780
 * \param label category label
 
781
 * \param pcats pointer to Categories structure
 
782
 *
 
783
 * \return
 
784
 */
 
785
int Rast_set_f_cat(const FCELL * rast1, const FCELL * rast2,
 
786
                   const char *label, struct Categories *pcats)
 
787
{
 
788
    return Rast_set_cat(rast1, rast2, label, pcats, FCELL_TYPE);
 
789
}
 
790
 
 
791
/*!
 
792
 * \brief Set a raster category label (DCELL)
 
793
 *
 
794
 * Adds the label for range <i>rast1</i> through <i>rast2</i> in
 
795
 * category structure <i>pcats</i>.
 
796
 *
 
797
 * \param rast1, rast2 raster values (range)
 
798
 * \param label category label
 
799
 * \param pcats pointer to Categories structure
 
800
 *
 
801
 * \return -1 on error
 
802
 * \return 0 if null value detected
 
803
 * \return 1 on success
 
804
 */
 
805
int Rast_set_d_cat(const DCELL * rast1, const DCELL * rast2,
 
806
                   const char *label, struct Categories *pcats)
 
807
{
 
808
    long len;
 
809
    DCELL dtmp1, dtmp2;
 
810
    int i;
 
811
    char *descr;
 
812
 
 
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))
 
816
        return 0;
 
817
    if (Rast_is_d_null_value(rast2))
 
818
        return 0;
 
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 */
 
827
 
 
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]);
 
837
            return 1;
 
838
        }
 
839
    }
 
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,
 
843
                        pcats->ncats);
 
844
    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 */
 
850
            pcats->ncats--;
 
851
            return -1;
 
852
        }
 
853
        /* DEBUG fprintf(stderr,"Rast_set_d_cat(): pcats->nalloc = %d, pcats->labels = (%p), len = %d\n",pcats->nalloc,pcats->labels,(int)len); */
 
854
        if (pcats->nalloc) {
 
855
            /* DEBUG fprintf(stderr,"Rast_set_d_cat(): Realloc-ing pcats->labels (%p)\n",pcats->labels); */
 
856
            pcats->labels =
 
857
                (char **)G_realloc((char *)pcats->labels, (int)len);
 
858
        }
 
859
        else {
 
860
            /* DEBUG fprintf(stderr,"Rast_set_d_cat(): alloc-ing new labels pointer array\n"); */
 
861
            pcats->labels = (char **)G_malloc((int)len);
 
862
        }
 
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 */
 
867
            pcats->ncats--;
 
868
            return -1;
 
869
        }
 
870
        if (pcats->nalloc)
 
871
            pcats->marks = (int *)G_realloc((char *)pcats->marks, (int)len);
 
872
        else
 
873
            pcats->marks = (int *)G_malloc((int)len);
 
874
        pcats->nalloc += 256;
 
875
    }
 
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]);
 
880
    /* DEBUG
 
881
       fprintf (stderr, "%d %s\n", pcats->ncats - 1, pcats->labels[pcats->ncats - 1]);
 
882
     */
 
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); */
 
891
    return 1;
 
892
}
 
893
 
 
894
 
 
895
/*!
 
896
 * \brief Set a raster category label
 
897
 *
 
898
 * Adds the label for range <i>rast1</i> through <i>rast2</i> in
 
899
 * category structure <i>pcats</i>.
 
900
 *
 
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
 
905
 *
 
906
 * \return -1 on error
 
907
 * \return 0 if null value detected
 
908
 * \return 1 on success
 
909
 */
 
910
 
 
911
int Rast_set_cat(const void *rast1, const void *rast2,
 
912
                 const char *label,
 
913
                 struct Categories *pcats, RASTER_MAP_TYPE data_type)
 
914
{
 
915
    DCELL val1, val2;
 
916
 
 
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);
 
920
}
 
921
 
 
922
/*!
 
923
 * \brief Write raster category file
 
924
 *
 
925
 * \todo To be removed, replaced by Rast_write_cats().
 
926
 *
 
927
 * Writes the category file for the raster map <i>name</i> in the
 
928
 * current mapset from the <i>cats</i> structure.
 
929
 *
 
930
 * \param name map name
 
931
 * \param cats pointer to Categories structure
 
932
 *
 
933
 * \return void
 
934
 */
 
935
void Rast_write_cats(const char *name, struct Categories *cats)
 
936
{
 
937
    write_cats("cats", name, cats);
 
938
}
 
939
 
 
940
/*!
 
941
 * \brief Write vector category file
 
942
 *
 
943
 * <b>Note:</b> Used for only old vector format!
 
944
 *
 
945
 * \todo Move to the vector library.
 
946
 *
 
947
 * \param name map name
 
948
 * \param cats pointer to Categories structure
 
949
 *
 
950
 * \return void
 
951
 */
 
952
void Rast_write_vector_cats(const char *name, struct Categories *cats)
 
953
{
 
954
    write_cats("dig_cats", name, cats);
 
955
}
 
956
 
 
957
static void write_cats(const char *element, const char *name,
 
958
                       struct Categories *cats)
 
959
{
 
960
    FILE *fd;
 
961
    int i, fp_map;
 
962
    char *descr;
 
963
    DCELL val1, val2;
 
964
    char str1[100], str2[100];
 
965
 
 
966
    fd = G_fopen_new(element, name);
 
967
    if (!fd)
 
968
        G_fatal_error(_("Unable to open %s file for map <%s>"), element, name);
 
969
 
 
970
    /* write # cats - note # indicate 3.0 or later */
 
971
    fprintf(fd, "# %ld categories\n", (long)cats->num);
 
972
 
 
973
    /* title */
 
974
    fprintf(fd, "%s\n", cats->title != NULL ? cats->title : "");
 
975
 
 
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);
 
980
 
 
981
    /* if the map is integer or if this is a vector map, sort labels */
 
982
    if (strncmp(element, "dig", 3) == 0)
 
983
        fp_map = 0;
 
984
    else
 
985
        fp_map = Rast_map_is_fp(name, G_mapset());
 
986
    if (!fp_map)
 
987
        Rast_sort_cats(cats);
 
988
 
 
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])) {
 
994
            if (val1 == val2) {
 
995
                sprintf(str1, "%.10f", val1);
 
996
                G_trim_decimal(str1);
 
997
                fprintf(fd, "%s:%s\n", str1, descr != NULL ? descr : "");
 
998
            }
 
999
            else {
 
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 : "");
 
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
 */
 
1026
char *Rast_get_ith_d_cat(const struct Categories *pcats,
 
1027
                         int i, DCELL * rast1, DCELL * rast2)
 
1028
{
 
1029
    int index;
 
1030
 
 
1031
    if (i > pcats->ncats) {
 
1032
        Rast_set_d_null_value(rast1, 1);
 
1033
        Rast_set_d_null_value(rast2, 1);
 
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
 */
 
1054
char *Rast_get_ith_f_cat(const struct Categories *pcats,
 
1055
                         int i, void *rast1, 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
 */
 
1081
char *Rast_get_ith_c_cat(const struct Categories *pcats,
 
1082
                         int i, void *rast1, 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
 */
 
1109
char *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) largets data value for backwards
 
1137
 * compatibility.
 
1138
 *
 
1139
 * \param title title
 
1140
 * \param pcats pointer to Categories structure
 
1141
 */
 
1142
void 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;
 
1155
    Rast_quant_init(&pcats->q);
 
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
 */
 
1168
void Rast_set_cats_title(const char *title, struct Categories *pcats)
 
1169
{
 
1170
    if (title == NULL)
 
1171
        title = "";
 
1172
    pcats->title = G_store(title);
 
1173
    G_newlines_to_spaces(pcats->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
 */
 
1187
void 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);
 
1196
    G_newlines_to_spaces(pcats->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
 */
 
1210
void Rast_free_cats(struct Categories *pcats)
 
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
    }
 
1230
    Rast_quant_free(&pcats->q);
 
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
 */
 
1245
void Rast_copy_cats(struct Categories *pcats_to,
 
1246
                    const struct Categories *pcats_from)
 
1247
{
 
1248
    int i;
 
1249
    char *descr;
 
1250
    DCELL d1, d2;
 
1251
 
 
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);
 
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
 */
 
1266
int Rast_number_of_cats(struct Categories *pcats)
 
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
 */
 
1279
int Rast_sort_cats(struct Categories *pcats)
 
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);
 
1291
    Rast_free_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
                pcats, pcats->labels);
 
1303
        Rast_set_d_cat(&d1, &d2, descr, pcats);
 
1304
    }
 
1305
    Rast_free_cats(&save_cats);
 
1306
 
 
1307
    return 0;
 
1308
}
 
1309
 
 
1310
static int cmp(const void *aa, const void *bb)
 
1311
{
 
1312
    const int *a = aa, *b = bb;
 
1313
    DCELL min_rast1, min_rast2, max_rast1, max_rast2;
 
1314
    CELL index;
 
1315
 
 
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)
 
1321
        return -1;
 
1322
    if (min_rast1 > min_rast2)
 
1323
        return 1;
 
1324
    return 0;
 
1325
}