cindex.c 13 KB

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