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
check_status(const struct Map_info * Map)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
check_index(const struct Map_info * Map,int index)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 */
ci_search_cat(struct Cat_index * ci,int first,int cat)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 */
Vect_cidx_get_num_fields(const struct Map_info * Map)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 */
Vect_cidx_get_field_number(const struct Map_info * Map,int index)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 */
Vect_cidx_get_field_index(const struct Map_info * Map,int field)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 */
Vect_cidx_get_num_unique_cats_by_index(const struct Map_info * Map,int index)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 */
Vect_cidx_get_num_cats_by_index(const struct Map_info * Map,int index)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 */
Vect_cidx_get_num_types_by_index(const struct Map_info * Map,int field_index)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 */
Vect_cidx_get_type_count_by_index(const struct Map_info * Map,int field_index,int type_index,int * type,int * count)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 */
Vect_cidx_get_type_count(const struct Map_info * Map,int field,int type)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 */
Vect_cidx_get_cat_by_index(const struct Map_info * Map,int field_index,int cat_index,int * cat,int * type,int * id)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 */
Vect_cidx_get_unique_cats_by_index(struct Map_info * Map,int field_index,struct ilist * list)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 */
Vect_cidx_find_next(const struct Map_info * Map,int field_index,int cat,int type_mask,int start_index,int * type,int * id)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 */
Vect_cidx_find_all(const struct Map_info * Map,int layer,int type_mask,int cat,struct ilist * lines)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 if ((type_mask & GV_AREA) && type_mask != GV_AREA)
389 G_fatal_error(_("Mixing IDs of areas and primitives"));
390
391 idx = Vect_cidx_find_next(Map, field_index, cat,
392 type_mask, 0, &type, &line);
393
394 if (idx == -1) {
395 return;
396 }
397
398 do {
399 if (ci->cat[idx][0] != cat) {
400 break;
401 }
402 if (ci->cat[idx][1] & type_mask) {
403 Vect_list_append(lines, ci->cat[idx][2]);
404 }
405 idx++;
406 } while (idx < ci->n_cats);
407 return;
408 }
409
410 /*!
411 \brief Write (dump) category index in text form to file
412
413 \param Map pointer to Map_info structure
414 \param[out] out output file
415
416 \return 1 on success
417 \return 0 on error
418 */
Vect_cidx_dump(const struct Map_info * Map,FILE * out)419 int Vect_cidx_dump(const struct Map_info *Map, FILE * out)
420 {
421 int i, field, nfields, ntypes;
422
423 G_debug(2, "Vect_cidx_dump()");
424
425 check_status(Map);
426
427 nfields = Vect_cidx_get_num_fields(Map);
428 fprintf(out, "---------- CATEGORY INDEX DUMP: Number of layers: %d "
429 "--------------------------------------\n", nfields);
430
431 for (i = 0; i < nfields; i++) {
432 int j, nucats, ncats;
433
434 field = Vect_cidx_get_field_number(Map, i);
435 nucats = Vect_cidx_get_num_unique_cats_by_index(Map, i);
436 ncats = Vect_cidx_get_num_cats_by_index(Map, i);
437 ntypes = Vect_cidx_get_num_types_by_index(Map, i);
438
439 fprintf(out,
440 "Layer %6d number of unique cats: %7d number of "
441 "cats: %7d number of types: %d\n",
442 field, nucats, ncats, ntypes);
443 fprintf(out, SEP);
444
445 fprintf(out, " type | count\n");
446 for (j = 0; j < ntypes; j++) {
447 int type, count;
448
449 Vect_cidx_get_type_count_by_index(Map, i, j, &type, &count);
450 fprintf(out, " %5d | %9d\n", type, count);
451 }
452
453 fprintf(out, " category | type | line/area\n");
454 for (j = 0; j < ncats; j++) {
455 int cat, type, id;
456
457 Vect_cidx_get_cat_by_index(Map, i, j, &cat, &type, &id);
458 fprintf(out, "%9d | %4d | %9d\n", cat, type, id);
459 }
460
461 fprintf(out, SEP);
462 }
463
464 return 1;
465 }
466
467 /*!
468 \brief Save category index to binary file (cidx)
469
470 \param Map pointer to Map_info structure
471
472 \return 0 on success
473 \return 1 on error
474 */
Vect_cidx_save(struct Map_info * Map)475 int Vect_cidx_save(struct Map_info *Map)
476 {
477 struct Plus_head *plus;
478 char path[GPATH_MAX];
479 struct gvfile fp;
480
481 G_debug(2, "Vect_cidx_save()");
482 check_status(Map);
483
484 plus = &(Map->plus);
485
486 dig_file_init(&fp);
487
488 Vect__get_path(path, Map);
489 fp.file = G_fopen_new(path, GV_CIDX_ELEMENT);
490 if (fp.file == NULL) {
491 G_warning(_("Unable to create category index file for vector map <%s>"),
492 Vect_get_name(Map));
493 return 1;
494 }
495
496 /* set portable info */
497 dig_init_portable(&(plus->cidx_port), dig__byte_order_out());
498
499 if (0 > dig_write_cidx(&fp, plus)) {
500 G_warning(_("Error writing out category index file"));
501 return 1;
502 }
503
504 fclose(fp.file);
505
506 return 0;
507 }
508
509 /*!
510 \brief Read category index from cidx file if exists
511
512 \param Map pointer to Map_info structure
513 \param head_only read only header of the file
514
515 \return 0 on success
516 \return 1 if file does not exist
517 \return -1 error, file exists but cannot be read
518 */
Vect_cidx_open(struct Map_info * Map,int head_only)519 int Vect_cidx_open(struct Map_info *Map, int head_only)
520 {
521 int ret;
522 char file_path[GPATH_MAX], path[GPATH_MAX];
523 struct gvfile fp;
524 struct Plus_head *Plus;
525
526 G_debug(2, "Vect_cidx_open(): name = %s mapset= %s", Map->name,
527 Map->mapset);
528
529 Plus = &(Map->plus);
530
531 Vect__get_path(path, Map);
532 Vect__get_element_path(file_path, Map, GV_CIDX_ELEMENT);
533
534 if (access(file_path, F_OK) != 0) { /* does not exist */
535 return 1;
536 }
537
538 dig_file_init(&fp);
539 fp.file = G_fopen_old(path, GV_CIDX_ELEMENT, Map->mapset);
540
541 if (fp.file == NULL) { /* category index file is not available */
542 G_warning(_("Unable to open category index file for vector map <%s>"),
543 Vect_get_full_name(Map));
544 return -1;
545 }
546
547 /* load category index to memory */
548 ret = dig_read_cidx(&fp, Plus, head_only);
549
550 fclose(fp.file);
551
552 if (ret == 1) {
553 G_debug(3, "Cannot read cidx");
554 return -1;
555 }
556
557 return 0;
558 }
559