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