GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-6c790bf5c0
Vlib/cindex.c
Go to the documentation of this file.
1 /*!
2  \file lib/vector/Vlib/cindex.c
3 
4  \brief Vector library - category index management
5 
6  Higher level functions for reading/writing/manipulating vectors.
7 
8  (C) 2001-2013 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 Radim Blazek
14  \author Some contribution by Martin Landa <landa.martin gmail.com>
15  */
16 
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <grass/vector.h>
23 #include <grass/glocale.h>
24 
25 #include "local_proto.h"
26 
27 #define SEP \
28  "------------------------------------------------------------------------" \
29  "------------------\n"
30 
31 static void check_status(struct Map_info *Map)
32 {
33  if (!Map->plus.cidx_up_to_date)
34  G_fatal_error(_("Category index is not up to date"));
35 }
36 
37 static void check_index(struct Map_info *Map, int index)
38 {
39  if (index < 0 || index >= Map->plus.n_cidx)
40  G_fatal_error(_("Layer index out of range"));
41 }
42 
43 /* search for first occurrence of cat in cat index, starting at first */
44 static int ci_search_cat(struct Cat_index *ci, int first, int cat)
45 {
46  int lo, hi, mid;
47 
48  lo = first;
49  if (lo < 0)
50  lo = 0;
51  if (ci->cat[lo][0] > cat)
52  return -1;
53  if (ci->cat[lo][0] == cat)
54  return lo;
55 
56  hi = ci->n_cats - 1;
57  if (first > hi)
58  return -1;
59 
60  /* deferred test for equality */
61  while (lo < hi) {
62  mid = (lo + hi) >> 1;
63  if (ci->cat[mid][0] < cat)
64  lo = mid + 1;
65  else
66  hi = mid;
67  }
68  if (ci->cat[lo][0] == cat)
69  return lo;
70 
71  return -1;
72 }
73 
74 /*!
75  \brief Get number of layers in category index
76 
77  \param Map pointer to Map_info structure
78 
79  \return number of layers
80  */
82 {
83  check_status(Map);
84 
85  return Map->plus.n_cidx;
86 }
87 
88 /*!
89  \brief Get layer number for given index
90 
91  G_fatal_error() is called when index not found.
92 
93  \param Map pointer to Map_info structure
94  \param index layer index: from 0 to Vect_cidx_get_num_fields() - 1
95 
96  \return layer number
97  */
98 int Vect_cidx_get_field_number(struct Map_info *Map, int index)
99 {
100  check_status(Map);
101  check_index(Map, index);
102 
103  return Map->plus.cidx[index].field;
104 }
105 
106 /*!
107  \brief Get layer index for given layer number
108 
109  \param Map pointer to Map_info structure
110  \param field layer number
111 
112  \return layer index
113  \return -1 if not found
114  */
115 int Vect_cidx_get_field_index(struct Map_info *Map, int field)
116 {
117  int i;
118  const struct Plus_head *Plus;
119 
120  G_debug(2, "Vect_cidx_get_field_index() field = %d", field);
121 
122  check_status(Map);
123  Plus = &(Map->plus);
124 
125  for (i = 0; i < Plus->n_cidx; i++) {
126  if (Plus->cidx[i].field == field)
127  return i;
128  }
129 
130  return -1;
131 }
132 
133 /*!
134  \brief Get number of unique categories for given layer index
135 
136  G_fatal_error() is called when index not found.
137 
138  \param Map pointer to Map_info structure
139  \param index layer index (starts at 0)
140 
141  \return number of unique categories
142  \return -1 on error
143  */
145 {
146  check_status(Map);
147  check_index(Map, index);
148 
149  return Map->plus.cidx[index].n_ucats;
150 }
151 
152 /*!
153  \brief Get number of categories for given layer index
154 
155  \param Map pointer to Map_info structure
156  \param index layer index
157 
158  \return number of categories
159  \return -1 on error
160  */
161 int Vect_cidx_get_num_cats_by_index(struct Map_info *Map, int index)
162 {
163  check_status(Map);
164  check_index(Map, index);
165 
166  return Map->plus.cidx[index].n_cats;
167 }
168 
169 /*!
170  \brief Get number of feature types for given layer index
171 
172  G_fatal_error() is called when index not found.
173 
174  \param Map pointer to Map_info structure
175  \param field_index layer index
176 
177  \return number of feature types
178  \return -1 on error
179  */
180 int Vect_cidx_get_num_types_by_index(struct Map_info *Map, int field_index)
181 {
182  check_status(Map);
183  check_index(Map, field_index);
184 
185  return Map->plus.cidx[field_index].n_types;
186 }
187 
188 /*!
189  \brief Get count of feature types for given field and type index
190 
191  \param Map pointer to Map_info structure
192  \param field_index layer index
193  \param type_index type index
194  \param[out] type feature type (GV_POINT, ...)
195  \param[out] count number of features or NULL
196 
197  \return 1 on success
198  \return 0 on error
199  */
200 int Vect_cidx_get_type_count_by_index(struct Map_info *Map, int field_index,
201  int type_index, int *type, int *count)
202 {
203  check_status(Map);
204  check_index(Map, field_index);
205 
206  *type = Map->plus.cidx[field_index].type[type_index][0];
207  if (count)
208  *count = Map->plus.cidx[field_index].type[type_index][1];
209 
210  return 1;
211 }
212 
213 /*!
214  \brief Get count of features of certain type by layer and type
215 
216  \param Map pointer to Map_info structure
217  \param field layer number
218  \param type feature type
219 
220  \return feature count
221  \return 0 if no features, no such field or no such type in category index
222  */
223 int Vect_cidx_get_type_count(struct Map_info *Map, int field, int type)
224 {
225  int i, fi, count = 0;
226 
227  G_debug(3, "Vect_cidx_get_type_count() field = %d, type = %d", field, type);
228 
229  check_status(Map);
230 
231  if ((fi = Vect_cidx_get_field_index(Map, field)) < 0)
232  return 0; /* field not found */
233  G_debug(3, "field_index = %d", fi);
234 
235  G_debug(3, "ntypes = %d", Map->plus.cidx[fi].n_types);
236  for (i = 0; i < Map->plus.cidx[fi].n_types; i++) {
237  int tp, cnt;
238 
239  tp = Map->plus.cidx[fi].type[i][0];
240  cnt = Map->plus.cidx[fi].type[i][1];
241  if (tp & type)
242  count += cnt;
243  G_debug(3, "%d tp = %d, cnt= %d count = %d", i, tp, cnt, count);
244  }
245 
246  return count;
247 }
248 
249 /*!
250  \brief Get category, feature type and id for given layer and category index
251 
252  \param Map pointer to Map_info structure
253  \param field_index layer index
254  \param cat_index category index
255  \param[out] cat category number
256  \param[out] type feature type
257  \param[out] id feature id
258 
259  \return 1 on success
260  \return 0 on error
261  */
262 int Vect_cidx_get_cat_by_index(struct Map_info *Map, int field_index,
263  int cat_index, int *cat, int *type, int *id)
264 {
265  check_status(Map); /* This check is slow ? */
266  check_index(Map, field_index);
267 
268  if (cat_index < 0 || cat_index >= Map->plus.cidx[field_index].n_cats)
269  G_fatal_error(_("Category index out of range"));
270 
271  *cat = Map->plus.cidx[field_index].cat[cat_index][0];
272  *type = Map->plus.cidx[field_index].cat[cat_index][1];
273  *id = Map->plus.cidx[field_index].cat[cat_index][2];
274 
275  return 1;
276 }
277 
278 /*!
279  \brief Get list of unique categories for given layer index
280 
281  \param Map pointer to Map_info structure
282  \param field_index layer index
283  \param[out] list output list of cats
284 
285  \return 1 on success
286  \return 0 on error
287  */
288 int Vect_cidx_get_unique_cats_by_index(struct Map_info *Map, int field_index,
289  struct ilist *list)
290 {
291  int c;
292  struct Cat_index *ci;
293 
294  check_status(Map);
295  check_index(Map, field_index);
296 
297  ci = &(Map->plus.cidx[field_index]);
298 
299  /* force sorting index -- really needed? */
300  dig_cidx_sort(&(Map->plus));
301 
303  if (ci->n_cats > 0)
304  Vect_list_append(list, ci->cat[0][0]);
305  for (c = 1; c < ci->n_cats; c++) {
306  if (ci->cat[c][0] != ci->cat[c - 1][0])
307  Vect_list_append(list, ci->cat[c][0]);
308  }
309 
310  return list->n_values == ci->n_ucats ? 1 : 0;
311 }
312 
313 /*!
314  \brief Find next line/area id for given category, start_index and type_mask
315 
316  \param Map pointer to Map_info structure
317  \param field_index layer index
318  \param cat category number
319  \param type_mask requested feature type
320  \param start_index start search at this index (0 - whole category index)
321  \param[out] type returned type
322  \param[out] id returned line/area id
323 
324  \return index to array
325  \return -1 not found
326  */
327 int Vect_cidx_find_next(struct Map_info *Map, int field_index, int cat,
328  int type_mask, int start_index, int *type, int *id)
329 {
330  int cat_index;
331  struct Cat_index *ci;
332 
333  G_debug(3,
334  "Vect_cidx_find_next() cat = %d, type_mask = %d, start_index = %d",
335  cat, type_mask, start_index);
336 
337  check_status(Map); /* This check is slow ? */
338  check_index(Map, field_index);
339  *type = *id = 0;
340 
341  /* pointer to category index */
342  ci = &(Map->plus.cidx[field_index]);
343 
344  cat_index = ci_search_cat(ci, start_index, cat);
345  G_debug(3, "cat_index = %d", cat_index);
346 
347  if (cat_index < 0)
348  return -1;
349 
350  do {
351  G_debug(3, " cat_index = %d", cat_index);
352  if (ci->cat[cat_index][0] == cat && ci->cat[cat_index][1] & type_mask) {
353  *type = ci->cat[cat_index][1];
354  *id = ci->cat[cat_index][2];
355  G_debug(3, " type match -> record found");
356  return cat_index;
357  }
358  cat_index++;
359  } while (cat_index < ci->n_cats);
360 
361  return -1;
362 }
363 
364 /*!
365  \brief Find all line/area id's for given category
366 
367  \param Map pointer to Map_info structure
368  \param layer layer number
369  \param type_mask feature type of objects to search for
370  \param cat category number
371  \param[out] lines array of ids of found lines/points
372  */
373 void Vect_cidx_find_all(struct Map_info *Map, int layer, int type_mask, int cat,
374  struct ilist *lines)
375 {
376  int type, line;
377  struct Cat_index *ci;
378  int field_index, idx;
379 
380  Vect_reset_list(lines);
381  field_index = Vect_cidx_get_field_index(Map, layer);
382 
383  if (field_index == -1) {
384  /* not found */
385  return;
386  }
387  ci = &(Map->plus.cidx[field_index]);
388 
389  if ((type_mask & GV_AREA) && type_mask != GV_AREA)
390  G_fatal_error(_("Mixing IDs of areas and primitives"));
391 
392  idx =
393  Vect_cidx_find_next(Map, field_index, cat, type_mask, 0, &type, &line);
394 
395  if (idx == -1) {
396  return;
397  }
398 
399  do {
400  if (ci->cat[idx][0] != cat) {
401  break;
402  }
403  if (ci->cat[idx][1] & type_mask) {
404  Vect_list_append(lines, ci->cat[idx][2]);
405  }
406  idx++;
407  } while (idx < ci->n_cats);
408  return;
409 }
410 
411 /*!
412  \brief Write (dump) category index in text form to file
413 
414  \param Map pointer to Map_info structure
415  \param[out] out output file
416 
417  \return 1 on success
418  \return 0 on error
419  */
420 int Vect_cidx_dump(struct Map_info *Map, FILE *out)
421 {
422  int i, field, nfields, ntypes;
423 
424  G_debug(2, "Vect_cidx_dump()");
425 
426  check_status(Map);
427 
428  nfields = Vect_cidx_get_num_fields(Map);
429  fprintf(out,
430  "---------- CATEGORY INDEX DUMP: Number of layers: %d "
431  "--------------------------------------\n",
432  nfields);
433 
434  for (i = 0; i < nfields; i++) {
435  int j, nucats, ncats;
436 
439  ncats = Vect_cidx_get_num_cats_by_index(Map, i);
440  ntypes = Vect_cidx_get_num_types_by_index(Map, i);
441 
442  fprintf(out,
443  "Layer %6d number of unique cats: %7d number of "
444  "cats: %7d number of types: %d\n",
445  field, nucats, ncats, ntypes);
446  fprintf(out, SEP);
447 
448  fprintf(out, " type | count\n");
449  for (j = 0; j < ntypes; j++) {
450  int type, count;
451 
453  fprintf(out, " %5d | %9d\n", type, count);
454  }
455 
456  fprintf(out, " category | type | line/area\n");
457  for (j = 0; j < ncats; j++) {
458  int cat, type, id;
459 
460  Vect_cidx_get_cat_by_index(Map, i, j, &cat, &type, &id);
461  fprintf(out, "%9d | %4d | %9d\n", cat, type, id);
462  }
463 
464  fprintf(out, SEP);
465  }
466 
467  return 1;
468 }
469 
470 /*!
471  \brief Save category index to binary file (cidx)
472 
473  \param Map pointer to Map_info structure
474 
475  \return 0 on success
476  \return 1 on error
477  */
478 int Vect_cidx_save(struct Map_info *Map)
479 {
480  struct Plus_head *plus;
481  char path[GPATH_MAX];
482  struct gvfile fp;
483 
484  G_debug(2, "Vect_cidx_save()");
485  check_status(Map);
486 
487  plus = &(Map->plus);
488 
489  dig_file_init(&fp);
490 
491  Vect__get_path(path, Map);
493  if (fp.file == NULL) {
494  G_warning(_("Unable to create category index file for vector map <%s>"),
495  Vect_get_name(Map));
496  return 1;
497  }
498 
499  /* set portable info */
501 
502  if (0 > dig_write_cidx(&fp, plus)) {
503  G_warning(_("Error writing out category index file"));
504  return 1;
505  }
506 
507  fclose(fp.file);
508 
509  return 0;
510 }
511 
512 /*!
513  \brief Read category index from cidx file if exists
514 
515  \param Map pointer to Map_info structure
516  \param head_only read only header of the file
517 
518  \return 0 on success
519  \return 1 if file does not exist
520  \return -1 error, file exists but cannot be read
521  */
522 int Vect_cidx_open(struct Map_info *Map, int head_only)
523 {
524  int ret;
525  char file_path[GPATH_MAX], path[GPATH_MAX];
526  struct gvfile fp;
527  struct Plus_head *Plus;
528 
529  G_debug(2, "Vect_cidx_open(): name = %s mapset= %s", Map->name,
530  Map->mapset);
531 
532  Plus = &(Map->plus);
533 
534  Vect__get_path(path, Map);
535  Vect__get_element_path(file_path, Map, GV_CIDX_ELEMENT);
536 
537  if (access(file_path, F_OK) != 0) { /* does not exist */
538  return 1;
539  }
540 
541  dig_file_init(&fp);
543 
544  if (fp.file == NULL) { /* category index file is not available */
545  G_warning(_("Unable to open category index file for vector map <%s>"),
546  Vect_get_full_name(Map));
547  return -1;
548  }
549 
550  /* load category index to memory */
551  ret = dig_read_cidx(&fp, Plus, head_only);
552 
553  fclose(fp.file);
554 
555  if (ret == 1) {
556  G_debug(3, "Cannot read cidx");
557  return -1;
558  }
559 
560  return 0;
561 }
int Vect_cidx_get_type_count_by_index(struct Map_info *Map, int field_index, int type_index, int *type, int *count)
Get count of feature types for given field and type index.
Definition: Vlib/cindex.c:200
int Vect_cidx_get_num_types_by_index(struct Map_info *Map, int field_index)
Get number of feature types for given layer index.
Definition: Vlib/cindex.c:180
int Vect_cidx_open(struct Map_info *Map, int head_only)
Read category index from cidx file if exists.
Definition: Vlib/cindex.c:522
int Vect_cidx_get_unique_cats_by_index(struct Map_info *Map, int field_index, struct ilist *list)
Get list of unique categories for given layer index.
Definition: Vlib/cindex.c:288
int Vect_cidx_find_next(struct Map_info *Map, int field_index, int cat, int type_mask, int start_index, int *type, int *id)
Find next line/area id for given category, start_index and type_mask.
Definition: Vlib/cindex.c:327
int Vect_cidx_get_num_cats_by_index(struct Map_info *Map, int index)
Get number of categories for given layer index.
Definition: Vlib/cindex.c:161
int Vect_cidx_get_type_count(struct Map_info *Map, int field, int type)
Get count of features of certain type by layer and type.
Definition: Vlib/cindex.c:223
int Vect_cidx_get_field_index(struct Map_info *Map, int field)
Get layer index for given layer number.
Definition: Vlib/cindex.c:115
int Vect_cidx_save(struct Map_info *Map)
Save category index to binary file (cidx)
Definition: Vlib/cindex.c:478
int Vect_cidx_get_cat_by_index(struct Map_info *Map, int field_index, int cat_index, int *cat, int *type, int *id)
Get category, feature type and id for given layer and category index.
Definition: Vlib/cindex.c:262
#define SEP
Definition: Vlib/cindex.c:27
int Vect_cidx_get_field_number(struct Map_info *Map, int index)
Get layer number for given index.
Definition: Vlib/cindex.c:98
void Vect_cidx_find_all(struct Map_info *Map, int layer, int type_mask, int cat, struct ilist *lines)
Find all line/area id's for given category.
Definition: Vlib/cindex.c:373
int Vect_cidx_dump(struct Map_info *Map, FILE *out)
Write (dump) category index in text form to file.
Definition: Vlib/cindex.c:420
int Vect_cidx_get_num_fields(struct Map_info *Map)
Get number of layers in category index.
Definition: Vlib/cindex.c:81
int Vect_cidx_get_num_unique_cats_by_index(struct Map_info *Map, int index)
Get number of unique categories for given layer index.
Definition: Vlib/cindex.c:144
#define NULL
Definition: ccmath.h:32
FILE * G_fopen_old(const char *, const char *, const char *)
Open a database file for reading.
Definition: gis/open.c:251
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
int G_debug(int, const char *,...) __attribute__((format(printf
FILE * G_fopen_new(const char *, const char *)
Open a new database file.
Definition: gis/open.c:219
const char * Vect_get_full_name(struct Map_info *)
Get fully qualified name of vector map.
int Vect_list_append(struct ilist *, int)
Append new item to the end of list if not yet present.
const char * Vect_get_name(struct Map_info *)
Get name of vector map.
int Vect_reset_list(struct ilist *)
Reset ilist structure.
#define GV_CIDX_ELEMENT
Native format, category index.
Definition: dig_defines.h:24
#define GV_AREA
Definition: dig_defines.h:189
int dig_write_cidx(struct gvfile *, struct Plus_head *)
Definition: cindex_rw.c:252
int dig__byte_order_out(void)
Get byte order.
Definition: portable.c:1008
int dig_read_cidx(struct gvfile *, struct Plus_head *, int)
Read spatial index file.
Definition: cindex_rw.c:296
void dig_init_portable(struct Port_info *, int)
Set Port_info structure to byte order of file.
Definition: portable.c:900
void dig_cidx_sort(struct Plus_head *)
void dig_file_init(struct gvfile *file)
Initialize gvfile structure.
Definition: file.c:171
#define GPATH_MAX
Definition: gis.h:194
#define _(str)
Definition: glocale.h:10
int count
Category index.
Definition: dig_structs.h:718
int(* cat)[3]
Array of cats (cat, type, lines/area)
Definition: dig_structs.h:734
int n_cats
Number of items in cat array.
Definition: dig_structs.h:726
int field
Field (layer) number.
Definition: dig_structs.h:722
int type[7][2]
Number of elements for each type.
Definition: dig_structs.h:754
int n_ucats
Number of unique cats (not updated)
Definition: dig_structs.h:738
Vector map info.
Definition: dig_structs.h:1243
char * mapset
Mapset name.
Definition: dig_structs.h:1320
char * name
Map name (for 4.0)
Definition: dig_structs.h:1316
struct Plus_head plus
Plus info (topology, version, ...)
Definition: dig_structs.h:1270
Basic topology-related info.
Definition: dig_structs.h:769
int n_cidx
Number of category indexes (one for each field/layer)
Definition: dig_structs.h:1125
struct Port_info cidx_port
Portability information for category index.
Definition: dig_structs.h:837
int cidx_up_to_date
Category index to be updated.
Definition: dig_structs.h:1140
struct Version_info cidx
Version info for category index file.
Definition: dig_structs.h:777
File definition.
Definition: dig_structs.h:94
FILE * file
File descriptor.
Definition: dig_structs.h:98
List of integers.
Definition: gis.h:706
Definition: manage.h:4
Definition: path.h:15
char * Vect__get_path(char *path, struct Map_info *Map)
Get map directory name (internal use only)
char * Vect__get_element_path(char *file_path, struct Map_info *Map, const char *element)
Get map element full path (internal use only)