cindex.c 12 KB

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