2
* \file lib/vector/Vlib/cats.c
4
4
* \brief Vector library - Category management
6
6
* Higher level functions for reading/writing/manipulating vectors.
8
* (C) 2001-2009 by the GRASS Development Team
10
* This program is free software under the
11
* GNU General Public License (>=v2).
12
* Read the file COPYING that comes with GRASS
15
* \author Original author CERL, probably Dave Gerdes or Mike
8
* (C) 2001-2012 by the GRASS Development Team
10
* This program is free software under the GNU General Public License
11
* (>=v2). Read the file COPYING that comes with GRASS for details.
13
* \author Original author CERL, probably Dave Gerdes or Mike Higgins
17
14
* \author Update to GRASS 5.7 Radim Blazek and David D. Gray.
18
15
* \author Various updates by Martin Landa <landa.martin gmail.com>
16
* \author Various updates by Markus Metz
21
19
#include <stdlib.h>
22
20
#include <string.h>
23
#include <grass/gis.h>
24
#include <grass/Vect.h>
21
#include <grass/vector.h>
22
#include <grass/dbmi.h>
25
23
#include <grass/glocale.h>
27
25
static int cmp(const void *pa, const void *pb);
28
struct line_cats *Vect__new_cats_struct(void);
26
static struct line_cats *Vect__new_cats_struct(void);
146
144
\brief Get first found category of given field.
148
'cat' is set to first category found or -1 if field was not found
150
\param[in] Cats line_cats structure
151
\param[in] field layer number
152
\param[in] cat pointer to variable where cat will be written
146
<em>cat</em> is set to first category found or -1 if field was not
149
\param Cats pointer line_cats structure
150
\param field layer number
151
\param[out] cat pointer to variable where cat will be written (can be NULL)
153
\return number of found cats for given field (first reported)
155
154
\return 0 layer does not exist
157
int Vect_cat_get(struct line_cats *Cats, int field, int *cat)
156
int Vect_cat_get(const struct line_cats *Cats, int field, int *cat)
160
/* field was not found */
161
165
/* check input value */
163
if (field < 1 || field > GV_FIELD_MAX)
166
if (field < 1 || field > GV_FIELD_MAX)
169
169
/* go through cats and find if field exist */
170
170
for (n = 0; n < Cats->n_cats; n++) {
171
171
if (Cats->field[n] == field) {
172
if (cat && ret == 0) {
177
/* field was not found */
248
247
\brief Delete field/cat from line_cats structure
250
\param[in] Cats line_cats structure
251
\param[in] field layer number
252
\param[in] cat category to be deleted or -1 to delete all cats of given field
249
\param[in,out] Cats line_cats structure
250
\param field layer number
251
\param cat category to be deleted or -1 to delete all cats of given field
253
\return number of categories deleted
255
254
\return 0 field/category number does not exist
257
256
int Vect_field_cat_del(struct line_cats *Cats, int field, int cat)
259
register int n, m, found = 0;
258
register int n, m, found;
261
260
/* check input value */
263
262
if (field < 1 || field > GV_FIELD_MAX)
267
return Vect_cat_del(Cats, field);
267
269
/* go through cats and find if field exist */
268
271
for (n = 0; n < Cats->n_cats; n++) {
269
if (Cats->field[n] == field && (Cats->cat[n] == cat || cat == -1)) {
270
for (m = n; m < Cats->n_cats - 1; m++) {
271
Cats->field[m] = Cats->field[m + 1];
272
Cats->cat[m] = Cats->cat[m + 1];
272
if (Cats->field[n] != field || Cats->cat[n] != cat) {
273
Cats->field[m] = Cats->field[n];
274
Cats->cat[m] = Cats->cat[n];
278
found = Cats->n_cats - m;
338
333
G_free((void *)p);
346
\brief Convert string of categories and cat ranges separated by commas to cat_list.
348
Examples of string: 2,3,5-9,20. str - input string
350
\param[in] str cat list string
351
\param[out] list result cat_list structure
339
\brief Converts string of categories and cat ranges separated by commas to cat_list.
341
\par Examples of string:
345
2,3,5-9,20\endverbatim
351
cat_list = Vect_new_cat_list()
353
Vect_str_to_cat_list(str, cat_list)
357
cat_list->n_ranges = 4
358
cat_list->min = {2, 3, 5, 20}
359
cat_list->max = {2, 3, 9, 20}
362
\param str category list as a string
363
\param[in,out] list pointer to cat_list structure
353
365
\return number of errors in ranges
476
\brief Convert cat_list struct to ordered array of unique integers.
478
Output array do not contain duplicate items.
480
Allocated array should be freed by G_free().
482
\param cat_list pointer to cat_list struct
483
\param[out] vals array of integers
484
\param[out] nvals number of values
487
\return -1 on failure
489
int Vect_cat_list_to_array(const struct cat_list *list, int **vals, int *nvals)
491
int i, j, k, n, n_cats, n_ucats, last_cat;
494
G_debug(1, "Vect_cat_list_to_array()");
498
for (i = 0; i < list->n_ranges; i++) {
499
n = list->max[i] - list->min[i] + 1;
504
cats = (int *) G_realloc(cats, sizeof(int) * (n_cats + n));
506
for (j = n_cats, k = 0; j < n_cats + n; j++, k++) {
507
cats[j] = list->min[i] + k;
513
qsort(cats, n_cats, sizeof(int), cmp);
515
/* skip duplicated values */
516
ucats = G_malloc(sizeof(int) * n_cats);
517
last_cat = ucats[0] = cats[0];
519
for (i = 1; i < n_cats; i++) {
520
if (last_cat == cats[i])
522
last_cat = ucats[n_ucats++] = cats[i];
526
/* reallocate array for unique values */
527
ucats = (int *) G_realloc(ucats, sizeof(int) * n_ucats);
464
536
\brief Check if category number is in list.
466
\param[in] cat category number
467
\param[in] list cat_list structure
538
\param cat category number
539
\param list cat_list structure
469
541
\return TRUE if cat is in list
470
\return FALSE if it is not
472
int Vect_cat_in_cat_list(int cat, struct cat_list *list)
544
int Vect_cat_in_cat_list(int cat, const struct cat_list *list)
556
\brief Set category constraints using 'where' or 'cats' option and layer number.
558
\param Map pointer to Map_info structure
559
\param layer layer number
560
\param where where statement
561
\param catstr category list as string
563
\return pointer to cat_list structure or NULL
565
struct cat_list *Vect_cats_set_constraint(struct Map_info *Map, int layer,
566
char *where, char *catstr)
568
struct cat_list *list = NULL;
572
G_warning(_("Layer number must be > 0 for category constraints"));
573
/* no valid constraints, all categories qualify */
577
/* where has precedence over cats */
579
struct field_info *Fi = NULL;
580
dbDriver *driver = NULL;
581
int ncats, *cats = NULL;
585
G_warning(_("'%s' and '%s' parameters were supplied, cats will be ignored"), "where", "cats");
587
Fi = Vect_get_field(Map, layer);
589
G_fatal_error(_("Database connection not defined for layer %d"),
593
G_verbose_message(_("Loading categories from table <%s>..."), Fi->table);
595
driver = db_start_driver_open_database(Fi->driver, Fi->database);
597
G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
598
Fi->database, Fi->driver);
600
ncats = db_select_int(driver, Fi->table, Fi->key, where,
603
G_fatal_error(_("Unable select records from table <%s>"),
605
G_verbose_message(_n("One category loaded", "%d categories loaded", ncats), ncats);
607
db_close_database_shutdown_driver(driver);
610
qsort(cats, ncats, sizeof(int), cmp);
612
/* remove duplicates */
614
for (i = 1; i < ncats; i++) {
615
if (cats[i] != cats[j - 1]) {
622
/* convert to cat list */
623
list = Vect_new_cat_list();
625
ret = Vect_array_to_cat_list(cats, ncats, list);
627
G_warning(_("No categories selected with '%s' option"), "where");
633
list = Vect_new_cat_list();
635
ret = Vect_str_to_cat_list(catstr, list);
637
G_warning(_("%d errors in '%s' option"), ret, "cats");
641
if (list->n_ranges < 1) {
642
Vect_destroy_cat_list(list);
653
\brief Check if categories match with category constraints.
655
\param Cats line_cats structure
656
\param layer layer number
657
\param list cat_list structure
659
\return 0 no match, categories are outside constraints
660
\return 1 match, categories are inside constraints
662
int Vect_cats_in_constraint(struct line_cats *Cats, int layer,
663
struct cat_list *list)
668
G_warning(_("Layer number must be > 0 for category constraints"));
669
/* no valid constraint, all categories qualify */
674
for (i = 0; i < Cats->n_cats; i++) {
675
if (Cats->field[i] == layer &&
676
Vect_cat_in_cat_list(Cats->cat[i], list)) {
683
for (i = 0; i < Cats->n_cats; i++) {
684
if (Cats->field[i] == layer)
484
693
\brief Check if category is in ordered array of integers.
486
\param[in] cat category number
487
\param[in] array ordered array of integers
488
\param[in] ncats number of categories in array
695
\param cat category number
696
\param array ordered array of integers
697
\param ncats number of categories in array
490
699
\return TRUE if cat is in list
491
700
\return FALSE if it is not
493
int Vect_cat_in_array(int cat, int *array, int ncats)
702
int Vect_cat_in_array(int cat, const int *array, int ncats)
497
706
i = bsearch((void *)&cat, (void *)array, (size_t) ncats,
498
707
sizeof(int), cmp);
712
/* return -1 if *p1 < *p2
713
* return 1 if *p1 > *p2
714
* return 0 if *p1 == *p2 */
506
715
static int cmp(const void *pa, const void *pb)
508
717
int *p1 = (int *)pa;