GRASS GIS 8 Programmer's Manual  8.5.0dev(2024)-602118adcc
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"));
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"));
171  return 0;
172  }
173 
174  for (i = 1; i <= n; i++) {
175  ltype = Vect_read_line(Map, NULL, Cats, i);
176 
177  if (!(ltype & type))
178  continue; /* is not specified type */
179 
180  if (!Vect_cat_get(Cats, field, &cat))
181  continue; /* No such field */
182 
183  if (Vect_cat_in_cat_list(cat, clist)) { /* cat is in list */
184  varray->c[i] = value;
185  ni++;
186  }
187  }
188  }
189 
191 
192  return ni;
193 }
194 
195 /* compare 2 integers in array */
196 static int cmp(const void *pa, const void *pb)
197 {
198  int *p1 = (int *)pa;
199  int *p2 = (int *)pb;
200 
201  if (*p1 < *p2)
202  return -1;
203  if (*p1 > *p2)
204  return 1;
205  return 0;
206 }
207 
208 /* check if cat is in array */
209 static int in_array(int *cats, size_t ncats, int cat)
210 {
211  int *p;
212 
213  p = (int *)bsearch((void *)&cat, cats, ncats, sizeof(int), cmp);
214 
215  if (p == NULL)
216  return 0;
217 
218  return 1;
219 }
220 
221 /*!
222  \brief Set values in 'varray' to 'value' from DB (where statement)
223 
224  I category of object of given type is in categories selected from
225  DB based on where statement (given without where). <em>type</em>
226  may be either: GV_AREA or: GV_POINT | GV_LINE | GV_BOUNDARY |
227  GV_CENTROID
228 
229  Array is not reset to zero before, but old values (if any > 0) are
230  overwritten. Array must be initialised by Vect_new_varray() call.
231 
232  \param Map vector map
233  \param field layer number
234  \param where where statement
235  \param type feature type
236  \param value value to set up
237  \param[out] varray varray structure to modify
238 
239  \return number of items set
240  \return -1 on error
241  */
242 int Vect_set_varray_from_db(struct Map_info *Map, int field, const char *where,
243  int type, int value, struct varray *varray)
244 {
245  int i, n, c, centr, *cats;
246  int ncats;
247  int ni = 0; /* number of items set */
248  int ltype; /* line type */
249  struct line_cats *Cats;
250  struct field_info *Fi;
251  dbDriver *driver;
252 
253  G_debug(4, "Vect_set_varray_from_db(): field = %d where = '%s'", field,
254  where);
255 
256  /* Note: use category index once available */
257 
258  /* Check type */
259  if ((type & GV_AREA) && (type & (GV_POINTS | GV_LINES))) {
260  G_warning(_("Mixed area and other type requested for vector array"));
261  return 0;
262  }
263 
264  Cats = Vect_new_cats_struct();
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);
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);
288  return -1;
289  }
290 
291  if (type & GV_AREA) { /* Areas */
292  n = Vect_get_num_areas(Map);
293 
294  /* IMHO varray should be allocated only when it's required AND only as
295  large as required as WHERE will create a small subset of all vector
296  features and thus on large datasets it's waste of memory to allocate
297  it for all features. */
298  if (n > varray->size) { /* not enough space */
299  G_warning(_("Not enough space in vector array"));
300  return 0;
301  }
302 
303  for (i = 1; i <= n; i++) {
304  centr = Vect_get_area_centroid(Map, i);
305  if (centr <= 0)
306  continue; /* No centroid */
307 
308  Vect_read_line(Map, NULL, Cats, centr);
309  /*if ( !Vect_cat_get(Cats, field, &cat) ) continue; No such field */
310  for (c = 0; c < Cats->n_cats; c++) {
311  if (Cats->field[c] == field &&
312  in_array(cats, ncats, Cats->cat[c])) {
313  varray->c[i] = value;
314  ni++;
315  break;
316  }
317  }
318 
319  /*
320  if ( in_array ( cats, ncats, cat ) ) {
321  varray->c[i] = value;
322  ni++;
323  }
324  */
325  }
326  }
327  else { /* Lines */
328  n = Vect_get_num_lines(Map);
329 
330  if (n > varray->size) { /* not enough space */
331  G_warning(_("Not enough space in vector array"));
332  return 0;
333  }
334 
335  for (i = 1; i <= n; i++) {
336  ltype = Vect_read_line(Map, NULL, Cats, i);
337 
338  if (!(ltype & type))
339  continue; /* is not specified type */
340 
341  /* if ( !Vect_cat_get(Cats, field, &cat) ) continue; No such field
342  */
343  for (c = 0; c < Cats->n_cats; c++) {
344  if (Cats->field[c] == field &&
345  in_array(cats, ncats, Cats->cat[c])) {
346  varray->c[i] = value;
347  ni++;
348  break;
349  }
350  }
351  /*
352  if ( in_array ( cats, ncats, cat ) ) {
353  varray->c[i] = value;
354  ni++;
355  }
356  */
357  }
358  }
359 
360  G_free(cats);
362 
363  return ni;
364 }
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:242
#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_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: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
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