GRASS 8 Programmer's Manual  8.5.0dev(2025)-c070206eb1
array.c
Go to the documentation of this file.
1 /*!
2  \file lib/vector/Vlib/array.c
3 
4  \brief Vector library - category array
5 
6  Higher level functions for reading/writing/manipulating vectors.
7 
8  (C) 2001-2009 by the GRASS Development Team
9 
10  This program is free software under the
11  GNU General Public License (>=v2).
12  Read the file COPYING that comes with GRASS
13  for details.
14 
15  \author Radim Blazek
16  */
17 
18 #include <stdlib.h>
19 #include <grass/dbmi.h>
20 #include <grass/vector.h>
21 #include <grass/glocale.h>
22 
23 /* function prototypes */
24 static int cmp(const void *pa, const void *pb);
25 static int in_array(int *cats, size_t ncats, int cat);
26 
27 /*!
28  \brief Create new struct varray and allocate space for given number of items.
29 
30  Space allocated is 'size + 1' so that lines are accessed by line id.
31  Array values are set to 0.
32 
33  \param size size of array
34 
35  \return pointer to new struct varray
36  \return NULL if failed
37  */
39 {
40  struct varray *p;
41 
42  p = (struct varray *)G_malloc(sizeof(struct varray));
43 
44  if (p == NULL)
45  return NULL;
46 
47  p->size = size;
48  p->c = (int *)G_calloc(sizeof(char) * size + 1, sizeof(int));
49 
50  if (p->c == NULL) {
51  G_free(p);
52  return NULL;
53  }
54 
55  return p;
56 }
57 
58 /*!
59  \brief Set values in 'varray' to 'value' from category string.
60 
61  If category of object of given type is in <em>cstring</em> (string
62  representing category list like: '1,3,5-7'). <em>type</em> may be
63  either: GV_AREA or: GV_POINT | GV_LINE | GV_BOUNDARY | GV_CENTROID
64 
65  Array is not reset to zero before, but old values (if any > 0) are
66  overwritten. Array must be initialised by Vect_new_varray() call.
67 
68  \param Map vector map
69  \param field layer number
70  \param cstring pointer to string with categories
71  \param type feature type
72  \param value value to set up
73  \param[out] varray varray structure to modify
74 
75  \return number of items set
76  \return -1 on error
77  */
78 int Vect_set_varray_from_cat_string(struct Map_info *Map, int field,
79  const char *cstring, int type, int value,
80  struct varray *varray)
81 {
82  int ret;
83  struct cat_list *Clist;
84 
85  G_debug(4, "Vect_set_varray_from_cat_string(): cstring = '%s'", cstring);
86 
87  Clist = Vect_new_cat_list();
88 
89  ret = Vect_str_to_cat_list(cstring, Clist);
90 
91  if (ret > 0)
92  G_warning(_("%d errors in category string"), ret);
93 
94  G_debug(4, " %d ranges in clist", Clist->n_ranges);
95 
96  ret = Vect_set_varray_from_cat_list(Map, field, Clist, type, value, varray);
97 
98  Vect_destroy_cat_list(Clist);
99 
100  return ret;
101 }
102 
103 /*!
104  \brief Set values in 'varray' to 'value' from category list
105 
106  If category of object of given type is in <em>clist</em> (category
107  list). <em>type</em> may be either: GV_AREA or: GV_POINT | GV_LINE
108  | GV_BOUNDARY | GV_CENTROID
109 
110  Array is not reset to zero before, but old values (if any > 0) are
111  overwritten. Array must be initialised by Vect_new_varray() call.
112 
113  \param Map vector map
114  \param field layer number
115  \param clist list of categories
116  \param type feature type
117  \param value value to set up
118  \param[out] varray varray structure to modify
119 
120  \return number of items set
121  \return -1 on error
122  */
124  struct cat_list *clist, int type, int value,
125  struct varray *varray)
126 {
127  int i, n, centr, cat;
128  int ni = 0; /* number of items set */
129  int ltype; /* line type */
130  struct line_cats *Cats;
131 
132  G_debug(4, "Vect_set_varray_from_cat_list(): field = %d", field);
133 
134  /* Check type */
135  if ((type & GV_AREA) && (type & (GV_POINTS | GV_LINES))) {
136  G_warning(_("Mixed area and other type requested for vector array"));
137  return 0;
138  }
139 
140  Cats = Vect_new_cats_struct();
141 
142  if (type & GV_AREA) { /* Areas */
143  n = Vect_get_num_areas(Map);
144 
145  if (n > varray->size) { /* not enough space */
146  G_warning(_("Not enough space in vector array"));
148  return 0;
149  }
150 
151  for (i = 1; i <= n; i++) {
152  centr = Vect_get_area_centroid(Map, i);
153  if (centr <= 0)
154  continue; /* No centroid */
155 
156  Vect_read_line(Map, NULL, Cats, centr);
157  if (!Vect_cat_get(Cats, field, &cat))
158  continue; /* No such field */
159 
160  if (Vect_cat_in_cat_list(cat, clist)) { /* cat is in list */
161  varray->c[i] = value;
162  ni++;
163  }
164  }
165  }
166  else { /* Lines */
167  n = Vect_get_num_lines(Map);
168 
169  if (n > varray->size) { /* not enough space */
170  G_warning(_("Not enough space in vector array"));
172  return 0;
173  }
174 
175  for (i = 1; i <= n; i++) {
176  ltype = Vect_read_line(Map, NULL, Cats, i);
177 
178  if (!(ltype & type))
179  continue; /* is not specified type */
180 
181  if (!Vect_cat_get(Cats, field, &cat))
182  continue; /* No such field */
183 
184  if (Vect_cat_in_cat_list(cat, clist)) { /* cat is in list */
185  varray->c[i] = value;
186  ni++;
187  }
188  }
189  }
190 
192 
193  return ni;
194 }
195 
196 /* compare 2 integers in array */
197 static int cmp(const void *pa, const void *pb)
198 {
199  int *p1 = (int *)pa;
200  int *p2 = (int *)pb;
201 
202  if (*p1 < *p2)
203  return -1;
204  if (*p1 > *p2)
205  return 1;
206  return 0;
207 }
208 
209 /* check if cat is in array */
210 static int in_array(int *cats, size_t ncats, int cat)
211 {
212  int *p;
213 
214  p = (int *)bsearch((void *)&cat, cats, ncats, sizeof(int), cmp);
215 
216  if (p == NULL)
217  return 0;
218 
219  return 1;
220 }
221 
222 /*!
223  \brief Set values in 'varray' to 'value' from DB (where statement)
224 
225  I category of object of given type is in categories selected from
226  DB based on where statement (given without where). <em>type</em>
227  may be either: GV_AREA or: GV_POINT | GV_LINE | GV_BOUNDARY |
228  GV_CENTROID
229 
230  Array is not reset to zero before, but old values (if any > 0) are
231  overwritten. Array must be initialised by Vect_new_varray() call.
232 
233  \param Map vector map
234  \param field layer number
235  \param where where statement
236  \param type feature type
237  \param value value to set up
238  \param[out] varray varray structure to modify
239 
240  \return number of items set
241  \return -1 on error
242  */
243 int Vect_set_varray_from_db(struct Map_info *Map, int field, const char *where,
244  int type, int value, struct varray *varray)
245 {
246  int i, n, c, centr, *cats;
247  int ncats;
248  int ni = 0; /* number of items set */
249  int ltype; /* line type */
250  struct line_cats *Cats;
251  struct field_info *Fi;
252  dbDriver *driver;
253 
254  G_debug(4, "Vect_set_varray_from_db(): field = %d where = '%s'", field,
255  where);
256 
257  /* Note: use category index once available */
258 
259  /* Check type */
260  if ((type & GV_AREA) && (type & (GV_POINTS | GV_LINES))) {
261  G_warning(_("Mixed area and other type requested for vector array"));
262  return 0;
263  }
264 
265  /* Select categories from DB to array */
266  Fi = Vect_get_field(Map, field);
267  if (Fi == NULL) {
268  G_warning(_("Database connection not defined for layer %d"), field);
269  return -1;
270  }
271 
273  if (driver == NULL) {
274  G_warning(_("Unable to open database <%s> by driver <%s>"),
275  Fi->database, Fi->driver);
277  return -1;
278  }
279 
280  ncats = db_select_int(driver, Fi->table, Fi->key, where, &cats);
281 
283 
284  if (ncats == -1) {
285  G_warning(
286  _("Unable to select record from table <%s> (key %s, where %s)"),
287  Fi->table, Fi->key, where);
289  return -1;
290  }
292  Cats = Vect_new_cats_struct();
293 
294  if (type & GV_AREA) { /* Areas */
295  n = Vect_get_num_areas(Map);
296 
297  /* IMHO varray should be allocated only when it's required AND only as
298  large as required as WHERE will create a small subset of all vector
299  features and thus on large datasets it's waste of memory to allocate
300  it for all features. */
301  if (n > varray->size) { /* not enough space */
302  G_warning(_("Not enough space in vector array"));
304  G_free(cats);
305  return 0;
306  }
307 
308  for (i = 1; i <= n; i++) {
309  centr = Vect_get_area_centroid(Map, i);
310  if (centr <= 0)
311  continue; /* No centroid */
312 
313  Vect_read_line(Map, NULL, Cats, centr);
314  /*if ( !Vect_cat_get(Cats, field, &cat) ) continue; No such field */
315  for (c = 0; c < Cats->n_cats; c++) {
316  if (Cats->field[c] == field &&
317  in_array(cats, ncats, Cats->cat[c])) {
318  varray->c[i] = value;
319  ni++;
320  break;
321  }
322  }
323 
324  /*
325  if ( in_array ( cats, ncats, cat ) ) {
326  varray->c[i] = value;
327  ni++;
328  }
329  */
330  }
331  }
332  else { /* Lines */
333  n = Vect_get_num_lines(Map);
334 
335  if (n > varray->size) { /* not enough space */
336  G_warning(_("Not enough space in vector array"));
338  G_free(cats);
339  return 0;
340  }
341 
342  for (i = 1; i <= n; i++) {
343  ltype = Vect_read_line(Map, NULL, Cats, i);
344 
345  if (!(ltype & type))
346  continue; /* is not specified type */
347 
348  /* if ( !Vect_cat_get(Cats, field, &cat) ) continue; No such field
349  */
350  for (c = 0; c < Cats->n_cats; c++) {
351  if (Cats->field[c] == field &&
352  in_array(cats, ncats, Cats->cat[c])) {
353  varray->c[i] = value;
354  ni++;
355  break;
356  }
357  }
358  /*
359  if ( in_array ( cats, ncats, cat ) ) {
360  varray->c[i] = value;
361  ni++;
362  }
363  */
364  }
365  }
366 
367  G_free(cats);
369 
370  return ni;
371 }
struct varray * Vect_new_varray(int size)
Create new struct varray and allocate space for given number of items.
Definition: array.c:38
int Vect_set_varray_from_cat_string(struct Map_info *Map, int field, const char *cstring, int type, int value, struct varray *varray)
Set values in 'varray' to 'value' from category string.
Definition: array.c:78
int Vect_set_varray_from_cat_list(struct Map_info *Map, int field, struct cat_list *clist, int type, int value, struct varray *varray)
Set values in 'varray' to 'value' from category list.
Definition: array.c:123
int Vect_set_varray_from_db(struct Map_info *Map, int field, const char *where, int type, int value, struct varray *varray)
Set values in 'varray' to 'value' from DB (where statement)
Definition: array.c:243
#define NULL
Definition: ccmath.h:32
Main header of GRASS DataBase Management Interface.
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_free(void *)
Free allocated memory.
Definition: gis/alloc.c:147
#define G_calloc(m, n)
Definition: defs/gis.h:95
void G_warning(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition: defs/gis.h:94
int G_debug(int, const char *,...) __attribute__((format(printf
plus_t Vect_get_num_lines(struct Map_info *)
Fetch number of features (points, lines, boundaries, centroids) in vector map.
Definition: level_two.c:75
plus_t Vect_get_num_areas(struct Map_info *)
Get number of areas in vector map.
Definition: level_two.c:87
int Vect_cat_in_cat_list(int, const struct cat_list *)
Check if category number is in list.
struct cat_list * Vect_new_cat_list(void)
Allocate memory for cat_list structure.
int Vect_str_to_cat_list(const char *, struct cat_list *)
Converts string of categories and cat ranges separated by commas to cat_list.
int Vect_cat_get(const struct line_cats *, int, int *)
Get first found category of given field.
void Vect_destroy_cats_struct(struct line_cats *)
Frees all memory associated with line_cats structure, including the struct itself.
int Vect_read_line(struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
struct field_info * Vect_get_field(struct Map_info *, int)
Get information about link to database (by layer number)
Definition: field.c:515
void Vect_destroy_field_info(struct field_info *)
Free a struct field_info and all memory associated with it.
Definition: field.c:633
void Vect_destroy_cat_list(struct cat_list *)
Frees allocated cat_list memory.
int Vect_get_area_centroid(struct Map_info *, int)
Returns centroid id for given area.
struct line_cats * Vect_new_cats_struct(void)
Creates and initializes line_cats structure.
#define GV_LINES
Definition: dig_defines.h:193
#define GV_POINTS
Definition: dig_defines.h:192
#define GV_AREA
Definition: dig_defines.h:189
const struct driver * driver
Definition: driver/init.c:25
#define _(str)
Definition: glocale.h:10
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 field
Category layer (field)
Definition: dig_structs.h:1701
Definition: driver.h:27
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
Feature category info.
Definition: dig_structs.h:1677
int * field
Array of layers (fields)
Definition: dig_structs.h:1681
int * cat
Array of categories.
Definition: dig_structs.h:1685
int n_cats
Number of categories attached to element.
Definition: dig_structs.h:1689
Vector array.
Definition: dig_structs.h:1751
int * c
Array.
Definition: dig_structs.h:1762
int size
Array size.
Definition: dig_structs.h:1755