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