GRASS GIS 8 Programmer's Manual  8.4.0dev(2023)-bfef3d3961
vector/Vlib/cats.c
Go to the documentation of this file.
1 /*!
2  * \file lib/vector/Vlib/cats.c
3  *
4  * \brief Vector library - Category management
5  *
6  * Higher level functions for reading/writing/manipulating vectors.
7  *
8  * (C) 2001-2012 by the GRASS Development Team
9  *
10  * This program is free software under the GNU General Public License
11  * (>=v2). Read the file COPYING that comes with GRASS for details.
12  *
13  * \author Original author CERL, probably Dave Gerdes or Mike Higgins
14  * \author Update to GRASS 5.7 Radim Blazek and David D. Gray.
15  * \author Various updates by Martin Landa <landa.martin gmail.com>
16  * \author Various updates by Markus Metz
17  */
18 
19 #include <stdlib.h>
20 #include <string.h>
21 #include <grass/vector.h>
22 #include <grass/dbmi.h>
23 #include <grass/glocale.h>
24 
25 static int cmp(const void *pa, const void *pb);
26 static struct line_cats *Vect__new_cats_struct(void);
27 
28 /*!
29  \brief Creates and initializes line_cats structure.
30 
31  This structure is used for reading and writing vector cats. The
32  library routines handle all memory allocation.
33 
34  To free allocated memory call Vect_destroy_cats_struct().
35 
36  \return struct line_cats *
37  \return NULL on error
38  */
40 {
41  struct line_cats *p;
42 
43  if (NULL == (p = Vect__new_cats_struct()))
44  G_fatal_error(_("Vect_new_cats_struct(): Out of memory"));
45 
46  return p;
47 }
48 
49 /*!
50  \brief Creates and initializes line_cats structure (lower level fn)
51 
52  This structure is used for reading and writing vector cats. The
53  library routines handle all memory allocation.
54 
55  \return struct line_cats *
56  */
57 static struct line_cats *Vect__new_cats_struct(void)
58 {
59  struct line_cats *p;
60 
61  p = (struct line_cats *)G_malloc(sizeof(struct line_cats));
62 
63  /* n_cats MUST be initialized to zero */
64  if (p)
65  p->n_cats = 0;
66 
67  if (p)
68  p->alloc_cats = 0;
69 
70  return p;
71 }
72 
73 /*!
74  \brief Frees all memory associated with line_cats structure,
75  including the struct itself.
76 
77  \param p line_cats structure
78  */
80 {
81  if (p) { /* probably a moot test */
82  if (p->n_cats) {
83  G_free((void *)p->field);
84  G_free((void *)p->cat);
85  }
86  G_free((void *)p);
87  }
88 }
89 
90 /*!
91  \brief Add new field/cat to category structure if doesn't exist
92  yet.
93 
94  \param[in,out] Cats line_cats structure
95  \param[in] field layer number
96  \param[in] cat category number
97 
98  \return number of categories
99  \return 0 if no space for new category in structure, n_cats would be >
100  GV_NCATS_MAX \return -1 on out of memory \return -2 if field out of range: 1
101  - GV_FIELD_MAX or cat out of range: 1 - GV_CAT_MAX
102  */
103 int Vect_cat_set(struct line_cats *Cats, int field, int cat)
104 {
105  register int n;
106 
107  /* check input values */
108  /* compiler may warn:
109  * comparison is always 0 due to limited range of data type
110  * but remember that limit is set to portable data type length
111  * and machine native size may be longer */
112  /*
113  if (field < 1 || field > GV_FIELD_MAX || cat < 0 || cat > GV_CAT_MAX)
114  return (-2);
115  */
116 
117  /* go through old cats and find if field/category exists */
118  for (n = 0; n < Cats->n_cats; n++) {
119  if (Cats->field[n] == field && Cats->cat[n] == cat)
120  return (1);
121  }
122 
123  /* field was not found so we shall append new cat */
124  /* test if space exist */
125  if (n >= GV_NCATS_MAX) {
127  _("Too many categories (%d), unable to set cat %d (layer %d)"),
128  Cats->n_cats, cat, field);
129  }
130 
131  if (Cats->n_cats == Cats->alloc_cats) {
132  if (0 > dig_alloc_cats(Cats, Cats->n_cats + 100))
133  return (-1);
134  }
135 
136  n = Cats->n_cats;
137  Cats->field[n] = field;
138  Cats->cat[n] = cat;
139  Cats->n_cats++;
140  return (1);
141 }
142 
143 /*!
144  \brief Get first found category of given field.
145 
146  <em>cat</em> is set to first category found or -1 if field was not
147  found
148 
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)
152 
153  \return number of found cats for given field (first reported)
154  \return 0 layer does not exist
155  */
156 int Vect_cat_get(const struct line_cats *Cats, int field, int *cat)
157 {
158  int n, ret;
159 
160  /* field was not found */
161  ret = 0;
162  if (cat)
163  *cat = -1;
164 
165  /* check input value */
166  if (field < 1 || field > GV_FIELD_MAX)
167  return (0);
168 
169  /* go through cats and find if field exist */
170  for (n = 0; n < Cats->n_cats; n++) {
171  if (Cats->field[n] == field) {
172  if (cat && ret == 0) {
173  *cat = Cats->cat[n];
174  }
175  ret++;
176  }
177  }
178 
179  return ret;
180 }
181 
182 /*!
183  \brief Get list of categories of given field.
184 
185  \param Cats line_cats structure
186  \param field layer number
187  \param[out] cats pointer to list where cats will be written
188 
189  \return number of found categories
190  \return -1 on invalid field
191  */
192 int Vect_field_cat_get(const struct line_cats *Cats, int field,
193  struct ilist *cats)
194 {
195  int n;
196 
197  /* reset list of categories */
198  Vect_reset_list(cats);
199 
200  /* check input value */
201  if (field < 1 || field > GV_FIELD_MAX)
202  return -1;
203 
204  /* go through cats and find if field exist */
205  for (n = 0; n < Cats->n_cats; n++) {
206  if (Cats->field[n] == field)
207  Vect_list_append(cats, Cats->cat[n]);
208  }
209 
210  return cats->n_values;
211 }
212 
213 /*!
214  \brief Delete all categories of given layer
215 
216  \param[in,out] Cats line_cats structure
217  \param field layer number
218 
219  \return number of categories deleted
220  \return 0 layer does not exist
221  */
222 int Vect_cat_del(struct line_cats *Cats, int field)
223 {
224  int n, m, found;
225 
226  /* check input value */
227  /*
228  if (field < 1 || field > GV_FIELD_MAX)
229  return (0);
230  */
231 
232  /* go through cats and find if field exist */
233  m = 0;
234  for (n = 0; n < Cats->n_cats; n++) {
235  if (Cats->field[n] != field) {
236  Cats->field[m] = Cats->field[n];
237  Cats->cat[m] = Cats->cat[n];
238  m++;
239  }
240  }
241  found = Cats->n_cats - m;
242  Cats->n_cats = m;
243 
244  return (found);
245 }
246 
247 /*!
248  \brief Delete field/cat from line_cats structure
249 
250  \param[in,out] Cats line_cats structure
251  \param field layer number
252  \param cat category to be deleted or -1 to delete all cats of given field
253 
254  \return number of categories deleted
255  \return 0 field/category number does not exist
256  */
257 int Vect_field_cat_del(struct line_cats *Cats, int field, int cat)
258 {
259  register int n, m, found;
260 
261  /* check input value */
262  /*
263  if (field < 1 || field > GV_FIELD_MAX)
264  return (0);
265  */
266 
267  if (cat == -1)
268  return Vect_cat_del(Cats, field);
269 
270  /* go through cats and find if field exist */
271  m = 0;
272  for (n = 0; n < Cats->n_cats; n++) {
273  if (Cats->field[n] != field || Cats->cat[n] != cat) {
274  Cats->field[m] = Cats->field[n];
275  Cats->cat[m] = Cats->cat[n];
276  m++;
277  }
278  }
279  found = Cats->n_cats - m;
280  Cats->n_cats = m;
281 
282  return (found);
283 }
284 
285 /*!
286  \brief Reset category structure to make sure cats structure is clean to be
287  re-used.
288 
289  I.e. it has no cats associated with it. Cats must have
290  previously been created with Vect_new_cats_struct()
291 
292  \param[out] Cats line_cats structure
293 
294  \return 0
295  */
296 int Vect_reset_cats(struct line_cats *Cats)
297 {
298  Cats->n_cats = 0;
299 
300  return 0;
301 }
302 
303 /*!
304  \brief Allocate memory for cat_list structure.
305 
306  \return pointer to allocated structure
307  \return NULL if out of memory
308  */
310 {
311  struct cat_list *p;
312 
313  p = (struct cat_list *)G_malloc(sizeof(struct cat_list));
314 
315  /* n_ranges MUST be initialized to zero */
316  if (p)
317  G_zero(p, sizeof(struct cat_list));
318 
319  return p;
320 }
321 
322 /*!
323  \brief Frees allocated cat_list memory.
324 
325  \param p pointer to line_cats structure
326  */
328 {
329  if (p) { /* probably a moot test */
330  if (p->n_ranges) {
331  G_free((void *)p->min);
332  G_free((void *)p->max);
333  }
334  G_free((void *)p);
335  }
336 }
337 
338 /*!
339  \brief Converts string of categories and cat ranges separated by commas to
340  cat_list.
341 
342  \par Examples of string:
343  \verbatim
344  5,6,7
345  3-9
346  2,3,5-9,20\endverbatim
347 
348  \par Example:
349  \code
350  ...
351  str = "2,3,5-9,20"
352  cat_list = Vect_new_cat_list()
353 
354  Vect_str_to_cat_list(str, cat_list)
355  \endcode
356  \verbatim
357  cat_list->field = 0
358  cat_list->n_ranges = 4
359  cat_list->min = {2, 3, 5, 20}
360  cat_list->max = {2, 3, 9, 20}
361  \endverbatim
362 
363  \param str category list as a string
364  \param[in,out] list pointer to cat_list structure
365 
366  \return number of errors in ranges
367  */
368 int Vect_str_to_cat_list(const char *str, struct cat_list *list)
369 {
370  int i, nr, l, err = 0;
371  const char *s, *e;
372  char buf[100];
373  int min, max;
374 
375  G_debug(3, "Vect_str_to_cat_list(): str = %s", str);
376 
377  list->n_ranges = 0;
378  l = strlen(str);
379 
380  /* find number of ranges */
381  nr = 1; /* one range */
382  for (i = 0; i < l; i++)
383  if (str[i] == ',')
384  nr++;
385 
386  /* allocate space */
387  if (list->alloc_ranges == 0) {
388  list->min = (int *)G_malloc(nr * sizeof(int));
389  list->max = (int *)G_malloc(nr * sizeof(int));
390  }
391  else if (nr > list->alloc_ranges) {
392  list->min = (int *)G_realloc((void *)list->min, nr * sizeof(int));
393  list->max = (int *)G_realloc((void *)list->max, nr * sizeof(int));
394  }
395 
396  /* go through string and read ranges */
397  i = 0;
398  s = str;
399 
400  while (s) {
401  e = (char *)strchr(s, ','); /* first comma */
402  if (e) {
403  l = e - s;
404  strncpy(buf, s, l);
405  buf[l] = '\0';
406  s = e + 1;
407  }
408  else {
409  strcpy(buf, s);
410  s = NULL;
411  }
412 
413  G_debug(3, " buf = %s", buf);
414  if (sscanf(buf, "%d-%d", &min, &max) == 2) {
415  }
416  else if (sscanf(buf, "%d", &min) == 1)
417  max = min;
418  else { /* error */
419 
420  G_warning(_("Unable to convert category string '%s' (from '%s') to "
421  "category range"),
422  buf, str);
423  err++;
424  continue;
425  }
426 
427  list->min[i] = min;
428  list->max[i] = max;
429  i++;
430  }
431 
432  list->n_ranges = i;
433 
434  return (err);
435 }
436 
437 /*!
438  \brief Convert ordered array of integers to cat_list structure.
439 
440  \param vals array of integers
441  \param nvals number of values
442  \param[in,out] list pointer to cat_list structure
443 
444  \return number of ranges
445  */
446 int Vect_array_to_cat_list(const int *vals, int nvals, struct cat_list *list)
447 {
448  int i, range;
449 
450  G_debug(1, "Vect_array_to_cat_list()");
451  range = -1;
452  for (i = 0; i < nvals; i++) {
453  if (i == 0 || (vals[i] - list->max[range]) > 1) {
454  range++;
455  if (range == list->alloc_ranges) {
456  list->alloc_ranges += 1000;
457  list->min = (int *)G_realloc((void *)list->min,
458  list->alloc_ranges * sizeof(int));
459  list->max = (int *)G_realloc((void *)list->max,
460  list->alloc_ranges * sizeof(int));
461  }
462  list->min[range] = vals[i];
463  list->max[range] = vals[i];
464  }
465  else {
466  list->max[range] = vals[i];
467  }
468  }
469 
470  list->n_ranges = range + 1;
471 
472  return (list->n_ranges);
473 }
474 
475 /*!
476  \brief Convert cat_list struct to ordered array of unique integers.
477 
478  Output array do not contain duplicate items.
479 
480  Allocated array should be freed by G_free().
481 
482  \param cat_list pointer to cat_list struct
483  \param[out] vals array of integers
484  \param[out] nvals number of values
485 
486  \return 0 on success
487  \return -1 on failure
488  */
489 int Vect_cat_list_to_array(const struct cat_list *list, int **vals, int *nvals)
490 {
491  int i, j, k, n, n_cats, n_ucats, last_cat;
492  int *cats, *ucats;
493 
494  G_debug(1, "Vect_cat_list_to_array()");
495 
496  *nvals = n_cats = 0;
497  cats = NULL;
498  for (i = 0; i < list->n_ranges; i++) {
499  n = list->max[i] - list->min[i] + 1;
500  if (n < 1)
501  return -1;
502 
503  /* realloc array */
504  cats = (int *)G_realloc(cats, sizeof(int) * (n_cats + n));
505 
506  for (j = n_cats, k = 0; j < n_cats + n; j++, k++) {
507  cats[j] = list->min[i] + k;
508  }
509  n_cats += n;
510  }
511 
512  /* sort array */
513  qsort(cats, n_cats, sizeof(int), cmp);
514 
515  /* skip duplicated values */
516  ucats = G_malloc(sizeof(int) * n_cats);
517  last_cat = ucats[0] = cats[0];
518  n_ucats = 1;
519  for (i = 1; i < n_cats; i++) {
520  if (last_cat == cats[i])
521  continue;
522  last_cat = ucats[n_ucats++] = cats[i];
523  }
524  G_free(cats);
525 
526  /* reallocate array for unique values */
527  ucats = (int *)G_realloc(ucats, sizeof(int) * n_ucats);
528 
529  *nvals = n_ucats;
530  *vals = ucats;
531 
532  return 0;
533 }
534 
535 /*!
536  \brief Check if category number is in list.
537 
538  \param cat category number
539  \param list cat_list structure
540 
541  \return TRUE if cat is in list
542  \return FALSE if not
543  */
544 int Vect_cat_in_cat_list(int cat, const struct cat_list *list)
545 {
546  int i;
547 
548  for (i = 0; i < list->n_ranges; i++)
549  if (cat >= list->min[i] && cat <= list->max[i])
550  return (TRUE);
551 
552  return (FALSE);
553 }
554 
555 /*!
556  \brief Set category constraints using 'where' or 'cats' option and layer
557  number.
558 
559  \param Map pointer to Map_info structure
560  \param layer layer number
561  \param where where statement
562  \param catstr category list as string
563 
564  \return pointer to cat_list structure or NULL
565  */
566 struct cat_list *Vect_cats_set_constraint(struct Map_info *Map, int layer,
567  char *where, char *catstr)
568 {
569  struct cat_list *list = NULL;
570  int ret;
571 
572  if (layer < 1) {
573  G_warning(_("Layer number must be > 0 for category constraints"));
574  /* no valid constraints, all categories qualify */
575  return list;
576  }
577 
578  /* where has precedence over cats */
579  if (where) {
580  struct field_info *Fi = NULL;
581  dbDriver *driver = NULL;
582  int ncats, *cats = NULL;
583  int i, j;
584 
585  if (catstr)
586  G_warning(_("'%s' and '%s' parameters were supplied, cats will be "
587  "ignored"),
588  "where", "cats");
589 
590  Fi = Vect_get_field(Map, layer);
591  if (!Fi) {
592  G_fatal_error(_("Database connection not defined for layer %d"),
593  layer);
594  }
595 
596  G_verbose_message(_("Loading categories from table <%s>..."),
597  Fi->table);
598 
600  if (driver == NULL)
601  G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
602  Fi->database, Fi->driver);
603 
604  ncats = db_select_int(driver, Fi->table, Fi->key, where, &cats);
605  if (ncats == -1)
606  G_fatal_error(_("Unable select records from table <%s>"),
607  Fi->table);
609  n_("One category loaded", "%d categories loaded", ncats), ncats);
610 
612 
613  /* sort */
614  qsort(cats, ncats, sizeof(int), cmp);
615 
616  /* remove duplicates */
617  j = 1;
618  for (i = 1; i < ncats; i++) {
619  if (cats[i] != cats[j - 1]) {
620  cats[j] = cats[i];
621  j++;
622  }
623  }
624  ncats = j;
625 
626  /* convert to cat list */
628 
629  ret = Vect_array_to_cat_list(cats, ncats, list);
630  if (ret == 0)
631  G_warning(_("No categories selected with '%s' option"), "where");
632 
633  if (cats)
634  G_free(cats);
635  }
636  else if (catstr) {
638 
639  ret = Vect_str_to_cat_list(catstr, list);
640  if (ret > 0)
641  G_warning(_("%d errors in '%s' option"), ret, "cats");
642  }
643 
644  if (list) {
645  if (list->n_ranges < 1) {
647  list = NULL;
648  }
649  else
650  list->field = layer;
651  }
652 
653  return list;
654 }
655 
656 /*!
657  \brief Check if categories match with category constraints.
658 
659  \param Cats line_cats structure
660  \param layer layer number
661  \param list cat_list structure
662 
663  \return 0 no match, categories are outside constraints
664  \return 1 match, categories are inside constraints
665  */
666 /* TODO:
667  * for GRASS 8, change return type:
668  * return a list of all category numbers that match the constraints
669  * return NULL if no category number matches the constraints
670  */
671 int Vect_cats_in_constraint(struct line_cats *Cats, int layer,
672  struct cat_list *list)
673 {
674  int i;
675 
676  if (layer < 1) {
677  G_warning(_("Layer number must be > 0 for category constraints"));
678  /* no valid constraint, all categories qualify */
679  return 1;
680  }
681 
682  if (list) {
683  for (i = 0; i < Cats->n_cats; i++) {
684  if (Cats->field[i] == layer &&
685  Vect_cat_in_cat_list(Cats->cat[i], list)) {
686  return 1;
687  }
688  }
689  return 0;
690  }
691 
692  for (i = 0; i < Cats->n_cats; i++) {
693  if (Cats->field[i] == layer)
694  return 1;
695  }
696 
697  return 0;
698 }
699 
700 /*!
701  \brief Check if category is in ordered array of integers.
702 
703  \param cat category number
704  \param array ordered array of integers
705  \param ncats number of categories in array
706 
707  \return TRUE if cat is in list
708  \return FALSE if it is not
709  */
710 int Vect_cat_in_array(int cat, const int *array, int ncats)
711 {
712  int *i;
713 
714  i = bsearch((void *)&cat, (void *)array, (size_t)ncats, sizeof(int), cmp);
715 
716  return (i != NULL);
717 }
718 
719 /* return -1 if *p1 < *p2
720  * return 1 if *p1 > *p2
721  * return 0 if *p1 == *p2 */
722 static int cmp(const void *pa, const void *pb)
723 {
724  int *p1 = (int *)pa;
725  int *p2 = (int *)pb;
726 
727  if (*p1 < *p2)
728  return -1;
729  return (*p1 > *p2);
730 }
#define NULL
Definition: ccmath.h:32
dbDriver * db_start_driver_open_database(const char *, const char *)
Open driver/database connection.
Definition: db.c:28
int db_close_database_shutdown_driver(dbDriver *)
Close driver/database connection.
Definition: db.c:61
int db_select_int(dbDriver *, const char *, const char *, const char *, int **)
Select array of ordered integers from table/column.
void G_zero(void *, int)
Zero out a buffer, buf, of length i.
Definition: gis/zero.c:23
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#define G_realloc(p, n)
Definition: defs/gis.h:115
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition: defs/gis.h:113
void void G_verbose_message(const char *,...) __attribute__((format(printf
int G_debug(int, const char *,...) __attribute__((format(printf
int Vect_list_append(struct ilist *, int)
Append new item to the end of list if not yet present.
struct field_info * Vect_get_field(struct Map_info *, int)
Get information about link to database (by layer number)
Definition: field.c:515
int Vect_reset_list(struct ilist *)
Reset ilist structure.
#define GV_FIELD_MAX
Maximum field.
Definition: dig_defines.h:217
#define GV_NCATS_MAX
Maximum number of categories for one element.
Definition: dig_defines.h:215
int dig_alloc_cats(struct line_cats *, int)
Allocate room for 'num' fields and category arrays in struct line_cats.
Definition: struct_alloc.c:380
#define min(x, y)
Definition: draw2.c:29
#define max(x, y)
Definition: draw2.c:30
#define TRUE
Definition: gis.h:79
#define FALSE
Definition: gis.h:83
#define n_(strs, strp, num)
Definition: glocale.h:11
#define _(str)
Definition: glocale.h:10
double l
Definition: r_raster.c:39
struct list * list
Definition: read_list.c:24
Vector map info.
Definition: dig_structs.h:1243
Category list.
Definition: dig_structs.h:1697
int n_ranges
Number of ranges.
Definition: dig_structs.h:1713
int * min
Array of minimum values.
Definition: dig_structs.h:1705
int * max
Array of maximum values.
Definition: dig_structs.h:1709
Definition: driver.h:21
Layer (old: field) information.
Definition: dig_structs.h:131
char * table
Name of DB table.
Definition: dig_structs.h:151
char * driver
Name of DB driver ('sqlite', 'dbf', ...)
Definition: dig_structs.h:143
char * database
Definition: dig_structs.h:147
char * key
Name of key column (usually 'cat')
Definition: dig_structs.h:155
List of integers.
Definition: gis.h:706
int n_values
Number of values in the list.
Definition: gis.h:714
Feature category info.
Definition: dig_structs.h:1677
int * field
Array of layers (fields)
Definition: dig_structs.h:1681
int alloc_cats
Allocated space for categories.
Definition: dig_structs.h:1693
int * cat
Array of categories.
Definition: dig_structs.h:1685
int n_cats
Number of categories attached to element.
Definition: dig_structs.h:1689
Definition: manage.h:4
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)
Definition: symbol/read.c:216
struct cat_list * Vect_new_cat_list(void)
Allocate memory for cat_list structure.
struct cat_list * Vect_cats_set_constraint(struct Map_info *Map, int layer, char *where, char *catstr)
Set category constraints using 'where' or 'cats' option and layer number.
void Vect_destroy_cats_struct(struct line_cats *p)
Frees all memory associated with line_cats structure, including the struct itself.
int Vect_cat_get(const struct line_cats *Cats, int field, int *cat)
Get first found category of given field.
int Vect_reset_cats(struct line_cats *Cats)
Reset category structure to make sure cats structure is clean to be re-used.
int Vect_field_cat_del(struct line_cats *Cats, int field, int cat)
Delete field/cat from line_cats structure.
int Vect_array_to_cat_list(const int *vals, int nvals, struct cat_list *list)
Convert ordered array of integers to cat_list structure.
int Vect_cat_in_array(int cat, const int *array, int ncats)
Check if category is in ordered array of integers.
int Vect_str_to_cat_list(const char *str, struct cat_list *list)
Converts string of categories and cat ranges separated by commas to cat_list.
int Vect_cat_in_cat_list(int cat, const struct cat_list *list)
Check if category number is in list.
int Vect_cat_list_to_array(const struct cat_list *list, int **vals, int *nvals)
Convert cat_list struct to ordered array of unique integers.
int Vect_field_cat_get(const struct line_cats *Cats, int field, struct ilist *cats)
Get list of categories of given field.
int Vect_cats_in_constraint(struct line_cats *Cats, int layer, struct cat_list *list)
Check if categories match with category constraints.
int Vect_cat_del(struct line_cats *Cats, int field)
Delete all categories of given layer.
struct line_cats * Vect_new_cats_struct(void)
Creates and initializes line_cats structure.
void Vect_destroy_cat_list(struct cat_list *p)
Frees allocated cat_list memory.
int Vect_cat_set(struct line_cats *Cats, int field, int cat)
Add new field/cat to category structure if doesn't exist yet.