cindex.c 12 KB

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