GRASS 8 Programmer's Manual 8.6.0dev(2026)-4bb960b182
Loading...
Searching...
No Matches
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 SPDX-FileCopyrightText: 2001-2013 GRASS Development Team
9 SPDX-License-Identifier: GPL-2.0-or-later
10
11 \author Radim Blazek
12 \author Some contribution by Martin Landa <landa.martin gmail.com>
13 */
14
15#include <stdlib.h>
16#include <string.h>
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <unistd.h>
20#include <grass/vector.h>
21#include <grass/glocale.h>
22
23#include "local_proto.h"
24
25#define SEP \
26 "------------------------------------------------------------------------" \
27 "------------------\n"
28
29static void check_status(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
35static void check_index(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 */
42static 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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
221int Vect_cidx_get_type_count(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, type);
226
227 check_status(Map);
228
229 if ((fi = Vect_cidx_get_field_index(Map, field)) < 0)
230 return 0; /* field not found */
231 G_debug(3, "field_index = %d", fi);
232
233 G_debug(3, "ntypes = %d", Map->plus.cidx[fi].n_types);
234 for (i = 0; i < Map->plus.cidx[fi].n_types; i++) {
235 int tp, cnt;
236
237 tp = Map->plus.cidx[fi].type[i][0];
238 cnt = Map->plus.cidx[fi].type[i][1];
239 if (tp & type)
240 count += cnt;
241 G_debug(3, "%d tp = %d, cnt= %d count = %d", i, tp, cnt, count);
242 }
243
244 return count;
245}
246
247/*!
248 \brief Get category, feature type and id for given layer and category index
249
250 \param Map pointer to Map_info structure
251 \param field_index layer index
252 \param cat_index category index
253 \param[out] cat category number
254 \param[out] type feature type
255 \param[out] id feature id
256
257 \return 1 on success
258 \return 0 on error
259 */
261 int cat_index, int *cat, int *type, int *id)
262{
263 check_status(Map); /* This check is slow ? */
264 check_index(Map, field_index);
265
266 if (cat_index < 0 || cat_index >= Map->plus.cidx[field_index].n_cats)
267 G_fatal_error(_("Category index out of range"));
268
269 *cat = Map->plus.cidx[field_index].cat[cat_index][0];
270 *type = Map->plus.cidx[field_index].cat[cat_index][1];
271 *id = Map->plus.cidx[field_index].cat[cat_index][2];
272
273 return 1;
274}
275
276/*!
277 \brief Get list of unique categories for given layer index
278
279 \param Map pointer to Map_info structure
280 \param field_index layer index
281 \param[out] list output list of cats
282
283 \return 1 on success
284 \return 0 on error
285 */
287 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
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 */
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",
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 \brief Find all line/area id's for given category
364
365 \param Map pointer to Map_info structure
366 \param layer layer number
367 \param type_mask feature type of objects to search for
368 \param cat category number
369 \param[out] lines array of ids of found lines/points
370 */
371void Vect_cidx_find_all(struct Map_info *Map, int layer, int type_mask, int cat,
372 struct ilist *lines)
373{
374 int type, line;
375 struct Cat_index *ci;
376 int field_index, idx;
377
378 Vect_reset_list(lines);
380
381 if (field_index == -1) {
382 /* not found */
383 return;
384 }
385 ci = &(Map->plus.cidx[field_index]);
386
387 if ((type_mask & GV_AREA) && type_mask != GV_AREA)
388 G_fatal_error(_("Mixing IDs of areas and primitives"));
389
390 idx =
392
393 if (idx == -1) {
394 return;
395 }
396
397 do {
398 if (ci->cat[idx][0] != cat) {
399 break;
400 }
401 if (ci->cat[idx][1] & type_mask) {
402 Vect_list_append(lines, ci->cat[idx][2]);
403 }
404 idx++;
405 } while (idx < ci->n_cats);
406 return;
407}
408
409/*!
410 \brief Write (dump) category index in text form to file
411
412 \param Map pointer to Map_info structure
413 \param[out] out output file
414
415 \return 1 on success
416 \return 0 on error
417 */
419{
420 int i, field, nfields, ntypes;
421
422 G_debug(2, "Vect_cidx_dump()");
423
424 check_status(Map);
425
427 fprintf(out,
428 "---------- CATEGORY INDEX DUMP: Number of layers: %d "
429 "--------------------------------------\n",
430 nfields);
431
432 for (i = 0; i < nfields; i++) {
433 int j, nucats, ncats;
434
439
440 fprintf(out,
441 "Layer %6d number of unique cats: %7d number of "
442 "cats: %7d number of types: %d\n",
443 field, nucats, ncats, ntypes);
444 fprintf(out, SEP);
445
446 fprintf(out, " type | count\n");
447 for (j = 0; j < ntypes; j++) {
448 int type, count;
449
451 fprintf(out, " %5d | %9d\n", type, count);
452 }
453
454 fprintf(out, " category | type | line/area\n");
455 for (j = 0; j < ncats; j++) {
456 int cat, type, id;
457
459 fprintf(out, "%9d | %4d | %9d\n", cat, type, id);
460 }
461
462 fprintf(out, SEP);
463 }
464
465 return 1;
466}
467
468/*!
469 \brief Save category index to binary file (cidx)
470
471 \param Map pointer to Map_info structure
472
473 \return 0 on success
474 \return 1 on error
475 */
477{
478 struct Plus_head *plus;
479 char path[GPATH_MAX];
480 struct gvfile fp;
481
482 G_debug(2, "Vect_cidx_save()");
483 check_status(Map);
484
485 plus = &(Map->plus);
486
487 dig_file_init(&fp);
488
491 if (fp.file == NULL) {
492 G_warning(_("Unable to create category index file for vector map <%s>"),
494 return 1;
495 }
496
497 /* set portable info */
499
500 if (0 > dig_write_cidx(&fp, plus)) {
501 G_warning(_("Error writing out category index file"));
502 fclose(fp.file);
503 return 1;
504 }
505
506 fclose(fp.file);
507
508 return 0;
509}
510
511/*!
512 \brief Read category index from cidx file if exists
513
514 \param Map pointer to Map_info structure
515 \param head_only read only header of the file
516
517 \return 0 on success
518 \return 1 if file does not exist
519 \return -1 error, file exists but cannot be read
520 */
521int Vect_cidx_open(struct Map_info *Map, int head_only)
522{
523 int ret;
525 struct gvfile fp;
526 struct Plus_head *Plus;
527
528 G_debug(2, "Vect_cidx_open(): name = %s mapset= %s", Map->name,
529 Map->mapset);
530
531 Plus = &(Map->plus);
532
535
536 if (access(file_path, F_OK) != 0) { /* does not exist */
537 return 1;
538 }
539
540 dig_file_init(&fp);
541 fp.file = G_fopen_old(path, GV_CIDX_ELEMENT, Map->mapset);
542
543 if (fp.file == NULL) { /* category index file is not available */
544 const char *map_name = Vect_get_full_name(Map);
545 G_warning(_("Unable to open category index file for vector map <%s>"),
546 map_name);
547 G_free((void *)map_name);
548 return -1;
549 }
550
551 /* load category index to memory */
552 ret = dig_read_cidx(&fp, Plus, head_only);
553
554 fclose(fp.file);
555
556 if (ret == 1) {
557 G_debug(3, "Cannot read cidx");
558 return -1;
559 }
560
561 return 0;
562}
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.
int Vect_cidx_get_num_types_by_index(struct Map_info *Map, int field_index)
Get number of feature types for given layer index.
int Vect_cidx_open(struct Map_info *Map, int head_only)
Read category index from cidx file if exists.
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.
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.
int Vect_cidx_get_num_cats_by_index(struct Map_info *Map, int index)
Get number of categories for given layer index.
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.
int Vect_cidx_get_field_index(struct Map_info *Map, int field)
Get layer index for given layer number.
int Vect_cidx_save(struct Map_info *Map)
Save category index to binary file (cidx)
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.
#define SEP
Definition Vlib/cindex.c:25
int Vect_cidx_get_field_number(struct Map_info *Map, int index)
Get layer number for given index.
Definition Vlib/cindex.c:96
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.
int Vect_cidx_dump(struct Map_info *Map, FILE *out)
Write (dump) category index in text form to file.
int Vect_cidx_get_num_fields(struct Map_info *Map)
Get number of layers in category index.
Definition Vlib/cindex.c:79
int Vect_cidx_get_num_unique_cats_by_index(struct Map_info *Map, int index)
Get number of unique categories for given layer index.
#define NULL
Definition ccmath.h:32
AMI_err name(char **stream_name)
Definition ami_stream.h:426
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:145
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
FILE * G_fopen_new(const char *, const char *)
Open a new database file.
Definition gis/open.c:218
FILE * G_fopen_old(const char *, const char *, const char *)
Open a database file for reading.
Definition gis/open.c:250
int G_debug(int, const char *,...) __attribute__((format(printf
const char * Vect_get_name(struct Map_info *)
Get 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_full_name(struct Map_info *)
Get fully qualified 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
int dig_write_cidx(struct gvfile *, struct Plus_head *)
Definition cindex_rw.c:249
int dig__byte_order_out(void)
Get byte order.
Definition portable.c:1006
int dig_read_cidx(struct gvfile *, struct Plus_head *, int)
Read spatial index file.
Definition cindex_rw.c:293
void dig_init_portable(struct Port_info *, int)
Set Port_info structure to byte order of file.
Definition portable.c:898
void dig_cidx_sort(struct Plus_head *)
void dig_file_init(struct gvfile *file)
Initialize gvfile structure.
Definition file.c:169
#define GPATH_MAX
Definition gis.h:196
#define _(str)
Definition glocale.h:10
int count
Category index.
int(* cat)[3]
Array of cats (cat, type, lines/area)
int n_cats
Number of items in cat array.
int field
Field (layer) number.
int type[7][2]
Number of elements for each type.
Vector map info.
Basic topology-related info.
struct Port_info cidx_port
Portability information for category index.
File definition.
Definition dig_structs.h:92
FILE * file
File descriptor.
Definition dig_structs.h:96
List of integers.
Definition gis.h:712
Definition manage.h:4
Definition path.h:15
#define access
Definition unistd.h:7
#define F_OK
Definition unistd.h:22
char * Vect__get_element_path(char *file_path, struct Map_info *Map, const char *element)
Get map element full path (internal use only)
char * Vect__get_path(char *path, struct Map_info *Map)
Get map directory name (internal use only)