cindex.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. /*!
  2. \file lib/vector/Vlib/cindex.c
  3. \brief Vector library - category index management
  4. Higher level functions for reading/writing/manipulating vectors.
  5. (C) 2001-2013 by the GRASS Development Team
  6. This program is free software under the GNU General Public License
  7. (>=v2). Read the file COPYING that comes with GRASS for details.
  8. \author Radim Blazek
  9. \author Some contribution by Martin Landa <landa.martin gmail.com>
  10. */
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #include <unistd.h>
  16. #include <grass/vector.h>
  17. #include <grass/glocale.h>
  18. #include "local_proto.h"
  19. #define SEP "------------------------------------------------------------------------------------------\n"
  20. static void check_status(const struct Map_info *Map)
  21. {
  22. if (!Map->plus.cidx_up_to_date)
  23. G_fatal_error(_("Category index is not up to date"));
  24. }
  25. static void check_index(const struct Map_info *Map, int index)
  26. {
  27. if (index < 0 || index >= Map->plus.n_cidx)
  28. G_fatal_error(_("Layer index out of range"));
  29. }
  30. /* search for first occurrence of cat in cat index, starting at first */
  31. static int ci_search_cat(struct Cat_index *ci, int first, int cat)
  32. {
  33. int lo, hi, mid;
  34. lo = first;
  35. if (lo < 0)
  36. lo = 0;
  37. if (ci->cat[lo][0] > cat)
  38. return -1;
  39. if (ci->cat[lo][0] == cat)
  40. return lo;
  41. hi = ci->n_cats - 1;
  42. if (first > hi)
  43. return -1;
  44. /* deferred test for equality */
  45. while (lo < hi) {
  46. mid = (lo + hi) >> 1;
  47. if (ci->cat[mid][0] < cat)
  48. lo = mid + 1;
  49. else
  50. hi = mid;
  51. }
  52. if (ci->cat[lo][0] == cat)
  53. return lo;
  54. return -1;
  55. }
  56. /*!
  57. \brief Get number of layers in category index
  58. \param Map pointer to Map_info structure
  59. \return number of layers
  60. */
  61. int Vect_cidx_get_num_fields(const struct Map_info *Map)
  62. {
  63. check_status(Map);
  64. return Map->plus.n_cidx;
  65. }
  66. /*!
  67. \brief Get layer number for given index
  68. G_fatal_error() is called when index not found.
  69. \param Map pointer to Map_info structure
  70. \param index layer index: from 0 to Vect_cidx_get_num_fields() - 1
  71. \return layer number
  72. */
  73. int Vect_cidx_get_field_number(const struct Map_info *Map, int index)
  74. {
  75. check_status(Map);
  76. check_index(Map, index);
  77. return Map->plus.cidx[index].field;
  78. }
  79. /*!
  80. \brief Get layer index for given layer number
  81. \param Map pointer to Map_info structure
  82. \param field layer number
  83. \return layer index
  84. \return -1 if not found
  85. */
  86. int Vect_cidx_get_field_index(const struct Map_info *Map, int field)
  87. {
  88. int i;
  89. const struct Plus_head *Plus;
  90. G_debug(2, "Vect_cidx_get_field_index() field = %d", field);
  91. check_status(Map);
  92. Plus = &(Map->plus);
  93. for (i = 0; i < Plus->n_cidx; i++) {
  94. if (Plus->cidx[i].field == field)
  95. return i;
  96. }
  97. return -1;
  98. }
  99. /*!
  100. \brief Get number of unique categories for given layer index
  101. G_fatal_error() is called when index not found.
  102. \param Map pointer to Map_info structure
  103. \param index layer index (starts at 0)
  104. \return number of unique categories
  105. \return -1 on error
  106. */
  107. int Vect_cidx_get_num_unique_cats_by_index(const struct Map_info *Map, int index)
  108. {
  109. check_status(Map);
  110. check_index(Map, index);
  111. return Map->plus.cidx[index].n_ucats;
  112. }
  113. /*!
  114. \brief Get number of categories for given layer index
  115. \param Map pointer to Map_info structure
  116. \param index layer index
  117. \return number of categories
  118. \return -1 on error
  119. */
  120. int Vect_cidx_get_num_cats_by_index(const struct Map_info *Map, int index)
  121. {
  122. check_status(Map);
  123. check_index(Map, index);
  124. return Map->plus.cidx[index].n_cats;
  125. }
  126. /*!
  127. \brief Get number of feature types for given layer index
  128. G_fatal_error() is called when index not found.
  129. \param Map pointer to Map_info structure
  130. \param field_index layer index
  131. \return number of feature types
  132. \return -1 on error
  133. */
  134. int Vect_cidx_get_num_types_by_index(const struct Map_info *Map, int field_index)
  135. {
  136. check_status(Map);
  137. check_index(Map, field_index);
  138. return Map->plus.cidx[field_index].n_types;
  139. }
  140. /*!
  141. \brief Get count of feature types for given field and type index
  142. \param Map pointer to Map_info structure
  143. \param field_index layer index
  144. \param type_index type index
  145. \param[out] type feature type (GV_POINT, ...)
  146. \param[out] count number of features or NULL
  147. \return 1 on success
  148. \return 0 on error
  149. */
  150. int Vect_cidx_get_type_count_by_index(const struct Map_info *Map, int field_index,
  151. int type_index, int *type, int *count)
  152. {
  153. check_status(Map);
  154. check_index(Map, field_index);
  155. *type = Map->plus.cidx[field_index].type[type_index][0];
  156. if (count)
  157. *count = Map->plus.cidx[field_index].type[type_index][1];
  158. return 1;
  159. }
  160. /*!
  161. \brief Get count of features of certain type by layer and type
  162. \param Map pointer to Map_info structure
  163. \param field layer number
  164. \param type feature type
  165. \return feature count
  166. \return 0 if no features, no such field or no such type in category index
  167. */
  168. int Vect_cidx_get_type_count(const struct Map_info *Map, int field, int type)
  169. {
  170. int i, fi, count = 0;
  171. G_debug(3, "Vect_cidx_get_type_count() field = %d, type = %d", field,
  172. type);
  173. check_status(Map);
  174. if ((fi = Vect_cidx_get_field_index(Map, field)) < 0)
  175. return 0; /* field not found */
  176. G_debug(3, "field_index = %d", fi);
  177. G_debug(3, "ntypes = %d", Map->plus.cidx[fi].n_types);
  178. for (i = 0; i < Map->plus.cidx[fi].n_types; i++) {
  179. int tp, cnt;
  180. tp = Map->plus.cidx[fi].type[i][0];
  181. cnt = Map->plus.cidx[fi].type[i][1];
  182. if (tp & type)
  183. count += cnt;
  184. G_debug(3, "%d tp = %d, cnt= %d count = %d", i, tp, cnt, count);
  185. }
  186. return count;
  187. }
  188. /*!
  189. \brief Get category, feature type and id for given layer and category index
  190. \param Map pointer to Map_info structure
  191. \param field_index layer index
  192. \param cat_index category index
  193. \param[out] cat category number
  194. \param[out] type feature type
  195. \param[out] id feature id
  196. \return 1 on success
  197. \return 0 on error
  198. */
  199. int Vect_cidx_get_cat_by_index(const struct Map_info *Map, int field_index,
  200. int cat_index, int *cat, int *type, int *id)
  201. {
  202. check_status(Map); /* This check is slow ? */
  203. check_index(Map, field_index);
  204. if (cat_index < 0 || cat_index >= Map->plus.cidx[field_index].n_cats)
  205. G_fatal_error(_("Category index out of range"));
  206. *cat = Map->plus.cidx[field_index].cat[cat_index][0];
  207. *type = Map->plus.cidx[field_index].cat[cat_index][1];
  208. *id = Map->plus.cidx[field_index].cat[cat_index][2];
  209. return 1;
  210. }
  211. /*!
  212. \brief Get list of unique categories for given layer index
  213. \param Map pointer to Map_info structure
  214. \param field_index layer index
  215. \param[out] list output list of cats
  216. \return 1 on success
  217. \return 0 on error
  218. */
  219. int Vect_cidx_get_unique_cats_by_index(struct Map_info *Map, int field_index, struct ilist *list)
  220. {
  221. int c;
  222. struct Cat_index *ci;
  223. check_status(Map);
  224. check_index(Map, field_index);
  225. ci = &(Map->plus.cidx[field_index]);
  226. /* force sorting index -- really needed? */
  227. dig_cidx_sort(&(Map->plus));
  228. Vect_reset_list(list);
  229. if (ci->n_cats > 0)
  230. Vect_list_append(list, ci->cat[0][0]);
  231. for (c = 1; c < ci->n_cats; c++) {
  232. if (ci->cat[c][0] != ci->cat[c - 1][0])
  233. Vect_list_append(list, ci->cat[c][0]);
  234. }
  235. return list->n_values == ci->n_ucats ? 1 : 0;
  236. }
  237. /*!
  238. \brief Find next line/area id for given category, start_index and type_mask
  239. \param Map pointer to Map_info structure
  240. \param field_index layer index
  241. \param cat category number
  242. \param type_mask requested feature type
  243. \param start_index start search at this index (0 - whole category index)
  244. \param[out] type returned type
  245. \param[out] id returned line/area id
  246. \return index to array
  247. \return -1 not found
  248. */
  249. int Vect_cidx_find_next(const struct Map_info *Map, int field_index, int cat,
  250. int type_mask, int start_index, int *type, int *id)
  251. {
  252. int cat_index;
  253. struct Cat_index *ci;
  254. G_debug(3,
  255. "Vect_cidx_find_next() cat = %d, type_mask = %d, start_index = %d",
  256. cat, type_mask, start_index);
  257. check_status(Map); /* This check is slow ? */
  258. check_index(Map, field_index);
  259. *type = *id = 0;
  260. /* pointer to category index */
  261. ci = &(Map->plus.cidx[field_index]);
  262. cat_index = ci_search_cat(ci, start_index, cat);
  263. G_debug(3, "cat_index = %d", cat_index);
  264. if (cat_index < 0)
  265. return -1;
  266. do {
  267. G_debug(3, " cat_index = %d", cat_index);
  268. if (ci->cat[cat_index][0] == cat && ci->cat[cat_index][1] & type_mask) {
  269. *type = ci->cat[cat_index][1];
  270. *id = ci->cat[cat_index][2];
  271. G_debug(3, " type match -> record found");
  272. return cat_index;
  273. }
  274. cat_index++;
  275. } while (cat_index < ci->n_cats);
  276. return -1;
  277. }
  278. /*!
  279. \brief Find all line/area id's for given category
  280. \param Map pointer to Map_info structure
  281. \param layer layer number
  282. \param type_mask feature type of objects to search for
  283. \param cat category number
  284. \param[out] lines array of ids of found lines/points
  285. */
  286. void Vect_cidx_find_all(const struct Map_info *Map, int layer, int type_mask,
  287. int cat, struct ilist *lines)
  288. {
  289. int type, line;
  290. struct Cat_index *ci;
  291. int field_index, idx;
  292. Vect_reset_list(lines);
  293. field_index = Vect_cidx_get_field_index(Map, layer);
  294. if (field_index == -1) {
  295. /* not found */
  296. return;
  297. }
  298. ci = &(Map->plus.cidx[field_index]);
  299. if ((type_mask & GV_AREA) && type_mask != GV_AREA)
  300. G_fatal_error(_("Mixing IDs of areas and primitives"));
  301. idx = Vect_cidx_find_next(Map, field_index, cat,
  302. type_mask, 0, &type, &line);
  303. if (idx == -1) {
  304. return;
  305. }
  306. do {
  307. if (ci->cat[idx][0] != cat) {
  308. break;
  309. }
  310. if (ci->cat[idx][1] & type_mask) {
  311. Vect_list_append(lines, ci->cat[idx][2]);
  312. }
  313. idx++;
  314. } while (idx < ci->n_cats);
  315. return;
  316. }
  317. /*!
  318. \brief Write (dump) category index in text form to file
  319. \param Map pointer to Map_info structure
  320. \param[out] out output file
  321. \return 1 on success
  322. \return 0 on error
  323. */
  324. int Vect_cidx_dump(const struct Map_info *Map, FILE * out)
  325. {
  326. int i, field, nfields, ntypes;
  327. G_debug(2, "Vect_cidx_dump()");
  328. check_status(Map);
  329. nfields = Vect_cidx_get_num_fields(Map);
  330. fprintf(out, "---------- CATEGORY INDEX DUMP: Number of layers: %d "
  331. "--------------------------------------\n", nfields);
  332. for (i = 0; i < nfields; i++) {
  333. int j, nucats, ncats;
  334. field = Vect_cidx_get_field_number(Map, i);
  335. nucats = Vect_cidx_get_num_unique_cats_by_index(Map, i);
  336. ncats = Vect_cidx_get_num_cats_by_index(Map, i);
  337. ntypes = Vect_cidx_get_num_types_by_index(Map, i);
  338. fprintf(out,
  339. "Layer %6d number of unique cats: %7d number of "
  340. "cats: %7d number of types: %d\n",
  341. field, nucats, ncats, ntypes);
  342. fprintf(out, SEP);
  343. fprintf(out, " type | count\n");
  344. for (j = 0; j < ntypes; j++) {
  345. int type, count;
  346. Vect_cidx_get_type_count_by_index(Map, i, j, &type, &count);
  347. fprintf(out, " %5d | %9d\n", type, count);
  348. }
  349. fprintf(out, " category | type | line/area\n");
  350. for (j = 0; j < ncats; j++) {
  351. int cat, type, id;
  352. Vect_cidx_get_cat_by_index(Map, i, j, &cat, &type, &id);
  353. fprintf(out, "%9d | %4d | %9d\n", cat, type, id);
  354. }
  355. fprintf(out, SEP);
  356. }
  357. return 1;
  358. }
  359. /*!
  360. \brief Save category index to binary file (cidx)
  361. \param Map pointer to Map_info structure
  362. \return 0 on success
  363. \return 1 on error
  364. */
  365. int Vect_cidx_save(struct Map_info *Map)
  366. {
  367. struct Plus_head *plus;
  368. char path[GPATH_MAX];
  369. struct gvfile fp;
  370. G_debug(2, "Vect_cidx_save()");
  371. check_status(Map);
  372. plus = &(Map->plus);
  373. dig_file_init(&fp);
  374. Vect__get_path(path, Map);
  375. fp.file = G_fopen_new(path, GV_CIDX_ELEMENT);
  376. if (fp.file == NULL) {
  377. G_warning(_("Unable to create category index file for vector map <%s>"),
  378. Vect_get_name(Map));
  379. return 1;
  380. }
  381. /* set portable info */
  382. dig_init_portable(&(plus->cidx_port), dig__byte_order_out());
  383. if (0 > dig_write_cidx(&fp, plus)) {
  384. G_warning(_("Error writing out category index file"));
  385. return 1;
  386. }
  387. fclose(fp.file);
  388. return 0;
  389. }
  390. /*!
  391. \brief Read category index from cidx file if exists
  392. \param Map pointer to Map_info structure
  393. \param head_only read only header of the file
  394. \return 0 on success
  395. \return 1 if file does not exist
  396. \return -1 error, file exists but cannot be read
  397. */
  398. int Vect_cidx_open(struct Map_info *Map, int head_only)
  399. {
  400. int ret;
  401. char file_path[GPATH_MAX], path[GPATH_MAX];
  402. struct gvfile fp;
  403. struct Plus_head *Plus;
  404. G_debug(2, "Vect_cidx_open(): name = %s mapset= %s", Map->name,
  405. Map->mapset);
  406. Plus = &(Map->plus);
  407. Vect__get_path(path, Map);
  408. Vect__get_element_path(file_path, Map, GV_CIDX_ELEMENT);
  409. if (access(file_path, F_OK) != 0) { /* does not exist */
  410. return 1;
  411. }
  412. dig_file_init(&fp);
  413. fp.file = G_fopen_old(path, GV_CIDX_ELEMENT, Map->mapset);
  414. if (fp.file == NULL) { /* category index file is not available */
  415. G_warning(_("Unable to open category index file for vector map <%s>"),
  416. Vect_get_full_name(Map));
  417. return -1;
  418. }
  419. /* load category index to memory */
  420. ret = dig_read_cidx(&fp, Plus, head_only);
  421. fclose(fp.file);
  422. if (ret == 1) {
  423. G_debug(3, "Cannot read cidx");
  424. return -1;
  425. }
  426. return 0;
  427. }