GRASS 8 Programmer's Manual 8.6.0dev(2026)-1d1e47ad9d
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 (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
31static 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
37static 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 */
44static 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 */
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 */
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 */
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 */
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 */
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 */
223int 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 */
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 */
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 */
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",
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 */
373void 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);
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 =
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 */
421{
422 int i, field, nfields, ntypes;
423
424 G_debug(2, "Vect_cidx_dump()");
425
426 check_status(Map);
427
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
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
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 */
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
493 if (fp.file == NULL) {
494 G_warning(_("Unable to create category index file for vector map <%s>"),
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 fclose(fp.file);
505 return 1;
506 }
507
508 fclose(fp.file);
509
510 return 0;
511}
512
513/*!
514 \brief Read category index from cidx file if exists
515
516 \param Map pointer to Map_info structure
517 \param head_only read only header of the file
518
519 \return 0 on success
520 \return 1 if file does not exist
521 \return -1 error, file exists but cannot be read
522 */
523int Vect_cidx_open(struct Map_info *Map, int head_only)
524{
525 int ret;
527 struct gvfile fp;
528 struct Plus_head *Plus;
529
530 G_debug(2, "Vect_cidx_open(): name = %s mapset= %s", Map->name,
531 Map->mapset);
532
533 Plus = &(Map->plus);
534
537
538 if (access(file_path, F_OK) != 0) { /* does not exist */
539 return 1;
540 }
541
542 dig_file_init(&fp);
543 fp.file = G_fopen_old(path, GV_CIDX_ELEMENT, Map->mapset);
544
545 if (fp.file == NULL) { /* category index file is not available */
546 const char *map_name = Vect_get_full_name(Map);
547 G_warning(_("Unable to open category index file for vector map <%s>"),
548 map_name);
549 G_free((void *)map_name);
550 return -1;
551 }
552
553 /* load category index to memory */
554 ret = dig_read_cidx(&fp, Plus, head_only);
555
556 fclose(fp.file);
557
558 if (ret == 1) {
559 G_debug(3, "Cannot read cidx");
560 return -1;
561 }
562
563 return 0;
564}
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: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.
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: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.
#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:147
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:221
FILE * G_fopen_old(const char *, const char *, const char *)
Open a database file for reading.
Definition gis/open.c:253
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: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:199
#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:715
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)