GRASS GIS 8 Programmer's Manual  8.5.0dev(2025)-565e82de51
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  */
38 
40 {
41  struct varray *p;
42 
43  p = (struct varray *)G_malloc(sizeof(struct varray));
44 
45  if (p == NULL)
46  return NULL;
47 
48  p->size = size;
49  p->c = (int *)G_calloc(sizeof(char) * size + 1, sizeof(int));
50 
51  if (p->c == NULL) {
52  G_free(p);
53  return NULL;
54  }
55 
56  return p;
57 }
58 
59 /*!
60  \brief Set values in 'varray' to 'value' from category string.
61 
62  If category of object of given type is in <em>cstring</em> (string
63  representing category list like: '1,3,5-7'). <em>type</em> may be
64  either: GV_AREA or: GV_POINT | GV_LINE | GV_BOUNDARY | GV_CENTROID
65 
66  Array is not reset to zero before, but old values (if any > 0) are
67  overwritten. Array must be initialised by Vect_new_varray() call.
68 
69  \param Map vector map
70  \param field layer number
71  \param cstring pointer to string with categories
72  \param type feature type
73  \param value value to set up
74  \param[out] varray varray structure to modify
75 
76  \return number of items set
77  \return -1 on error
78  */
79 int Vect_set_varray_from_cat_string(struct Map_info *Map, int field,
80  const char *cstring, int type, int value,
81  struct varray *varray)
82 {
83  int ret;
84  struct cat_list *Clist;
85 
86  G_debug(4, "Vect_set_varray_from_cat_string(): cstring = '%s'", cstring);
87 
88  Clist = Vect_new_cat_list();
89 
90  ret = Vect_str_to_cat_list(cstring, Clist);
91 
92  if (ret > 0)
93  G_warning(_("%d errors in category string"), ret);
94 
95  G_debug(4, " %d ranges in clist", Clist->n_ranges);
96 
97  ret = Vect_set_varray_from_cat_list(Map, field, Clist, type, value, varray);
98 
99  Vect_destroy_cat_list(Clist);
100 
101  return ret;
102 }
103 
104 /*!
105  \brief Set values in 'varray' to 'value' from category list
106 
107  If category of object of given type is in <em>clist</em> (category
108  list). <em>type</em> may be either: GV_AREA or: GV_POINT | GV_LINE
109  | GV_BOUNDARY | GV_CENTROID
110 
111  Array is not reset to zero before, but old values (if any > 0) are
112  overwritten. Array must be initialised by Vect_new_varray() call.
113 
114  \param Map vector map
115  \param field layer number
116  \param clist list of categories
117  \param type feature type
118  \param value value to set up
119  \param[out] varray varray structure to modify
120 
121  \return number of items set
122  \return -1 on error
123  */
125  struct cat_list *clist, int type, int value,
126  struct varray *varray)
127 {
128  int i, n, centr, cat;
129  int ni = 0; /* number of items set */
130  int ltype; /* line type */
131  struct line_cats *Cats;
132 
133  G_debug(4, "Vect_set_varray_from_cat_list(): field = %d", field);
134 
135  /* Check type */
136  if ((type & GV_AREA) && (type & (GV_POINTS | GV_LINES))) {
137  G_warning(_("Mixed area and other type requested for vector array"));
138  return 0;
139  }
140 
141  Cats = Vect_new_cats_struct();
142 
143  if (type & GV_AREA) { /* Areas */
144  n = Vect_get_num_areas(Map);
145 
146  if (n > varray->size) { /* not enough space */
147  G_warning(_("Not enough space in vector array"));
149  return 0;
150  }
151 
152  for (i = 1; i <= n; i++) {
153  centr = Vect_get_area_centroid(Map, i);
154  if (centr <= 0)
155  continue; /* No centroid */
156 
157  Vect_read_line(Map, NULL, Cats, centr);
158  if (!Vect_cat_get(Cats, field, &cat))
159  continue; /* No such field */
160 
161  if (Vect_cat_in_cat_list(cat, clist)) { /* cat is in list */
162  varray->c[i] = value;
163  ni++;
164  }
165  }
166  }
167  else { /* Lines */
168  n = Vect_get_num_lines(Map);
169 
170  if (n > varray->size) { /* not enough space */
171  G_warning(_("Not enough space in vector array"));
173  return 0;
174  }
175 
176  for (i = 1; i <= n; i++) {
177  ltype = Vect_read_line(Map, NULL, Cats, i);
178 
179  if (!(ltype & type))
180  continue; /* is not specified type */
181 
182  if (!Vect_cat_get(Cats, field, &cat))
183  continue; /* No such field */
184 
185  if (Vect_cat_in_cat_list(cat, clist)) { /* cat is in list */
186  varray->c[i] = value;
187  ni++;
188  }
189  }
190  }
191 
193 
194  return ni;
195 }
196 
197 /* compare 2 integers in array */
198 static int cmp(const void *pa, const void *pb)
199 {
200  int *p1 = (int *)pa;
201  int *p2 = (int *)pb;
202 
203  if (*p1 < *p2)
204  return -1;
205  if (*p1 > *p2)
206  return 1;
207  return 0;
208 }
209 
210 /* check if cat is in array */
211 static int in_array(int *cats, size_t ncats, int cat)
212 {
213  int *p;
214 
215  p = (int *)bsearch((void *)&cat, cats, ncats, sizeof(int), cmp);
216 
217  if (p == NULL)
218  return 0;
219 
220  return 1;
221 }
222 
223 /*!
224  \brief Set values in 'varray' to 'value' from DB (where statement)
225 
226  I category of object of given type is in categories selected from
227  DB based on where statement (given without where). <em>type</em>
228  may be either: GV_AREA or: GV_POINT | GV_LINE | GV_BOUNDARY |
229  GV_CENTROID
230 
231  Array is not reset to zero before, but old values (if any > 0) are
232  overwritten. Array must be initialised by Vect_new_varray() call.
233 
234  \param Map vector map
235  \param field layer number
236  \param where where statement
237  \param type feature type
238  \param value value to set up
239  \param[out] varray varray structure to modify
240 
241  \return number of items set
242  \return -1 on error
243  */
244 int Vect_set_varray_from_db(struct Map_info *Map, int field, const char *where,
245  int type, int value, struct varray *varray)
246 {
247  int i, n, c, centr, *cats;
248  int ncats;
249  int ni = 0; /* number of items set */
250  int ltype; /* line type */
251  struct line_cats *Cats;
252  struct field_info *Fi;
253  dbDriver *driver;
254 
255  G_debug(4, "Vect_set_varray_from_db(): field = %d where = '%s'", field,
256  where);
257 
258  /* Note: use category index once available */
259 
260  /* Check type */
261  if ((type & GV_AREA) && (type & (GV_POINTS | GV_LINES))) {
262  G_warning(_("Mixed area and other type requested for vector array"));
263  return 0;
264  }
265 
266  /* Select categories from DB to array */
267  Fi = Vect_get_field(Map, field);
268  if (Fi == NULL) {
269  G_warning(_("Database connection not defined for layer %d"), field);
270  return -1;
271  }
272 
274  if (driver == NULL) {
275  G_warning(_("Unable to open database <%s> by driver <%s>"),
276  Fi->database, Fi->driver);
278  return -1;
279  }
280 
281  ncats = db_select_int(driver, Fi->table, Fi->key, where, &cats);
282 
284 
285  if (ncats == -1) {
286  G_warning(
287  _("Unable to select record from table <%s> (key %s, where %s)"),
288  Fi->table, Fi->key, where);
290  return -1;
291  }
293  Cats = Vect_new_cats_struct();
294 
295  if (type & GV_AREA) { /* Areas */
296  n = Vect_get_num_areas(Map);
297 
298  /* IMHO varray should be allocated only when it's required AND only as
299  large as required as WHERE will create a small subset of all vector
300  features and thus on large datasets it's waste of memory to allocate
301  it for all features. */
302  if (n > varray->size) { /* not enough space */
303  G_warning(_("Not enough space in vector array"));
305  G_free(cats);
306  return 0;
307  }
308 
309  for (i = 1; i <= n; i++) {
310  centr = Vect_get_area_centroid(Map, i);
311  if (centr <= 0)
312  continue; /* No centroid */
313 
314  Vect_read_line(Map, NULL, Cats, centr);
315  /*if ( !Vect_cat_get(Cats, field, &cat) ) continue; No such field */
316  for (c = 0; c < Cats->n_cats; c++) {
317  if (Cats->field[c] == field &&
318  in_array(cats, ncats, Cats->cat[c])) {
319  varray->c[i] = value;
320  ni++;
321  break;
322  }
323  }
324 
325  /*
326  if ( in_array ( cats, ncats, cat ) ) {
327  varray->c[i] = value;
328  ni++;
329  }
330  */
331  }
332  }
333  else { /* Lines */
334  n = Vect_get_num_lines(Map);
335 
336  if (n > varray->size) { /* not enough space */
337  G_warning(_("Not enough space in vector array"));
339  G_free(cats);
340  return 0;
341  }
342 
343  for (i = 1; i <= n; i++) {
344  ltype = Vect_read_line(Map, NULL, Cats, i);
345 
346  if (!(ltype & type))
347  continue; /* is not specified type */
348 
349  /* if ( !Vect_cat_get(Cats, field, &cat) ) continue; No such field
350  */
351  for (c = 0; c < Cats->n_cats; c++) {
352  if (Cats->field[c] == field &&
353  in_array(cats, ncats, Cats->cat[c])) {
354  varray->c[i] = value;
355  ni++;
356  break;
357  }
358  }
359  /*
360  if ( in_array ( cats, ncats, cat ) ) {
361  varray->c[i] = value;
362  ni++;
363  }
364  */
365  }
366  }
367 
368  G_free(cats);
370 
371  return ni;
372 }
struct varray * Vect_new_varray(int size)
Create new struct varray and allocate space for given number of items.
Definition: array.c:39
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:79
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:124
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:244
#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_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#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