cindex.c 12 KB

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