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. * \author Radim Blazek
  9. *
  10. * (C) 2001-2007 by the GRASS Development Team
  11. *
  12. * This program is free software under the GNU General Public
  13. * License (>=v2). Read the file COPYING that comes with GRASS
  14. * for details.
  15. */
  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/Vect.h>
  23. #include <grass/glocale.h>
  24. static int cmp_cat(const void *pa, const void *pb);
  25. static void check_status(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[in] Map vector map
  33. \return number of layers
  34. */
  35. int Vect_cidx_get_num_fields(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[in] Map vector map
  43. \param[in] index layer index: from 0 to Vect_cidx_get_num_fields() - 1
  44. \return layer number
  45. */
  46. int Vect_cidx_get_field_number(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[in] Map vector map
  56. \param[in] field layer number
  57. \return layer index
  58. \return -1 if not found
  59. */
  60. int Vect_cidx_get_field_index(struct Map_info *Map, int field)
  61. {
  62. int i;
  63. 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[in] Map vector map
  76. \param[in] 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(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[in] Map vector map
  90. \param[in] index layer index
  91. \return number of categories
  92. \return -1 on error
  93. */
  94. int Vect_cidx_get_num_cats_by_index(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[in] Map vector map
  104. \param[in] field_index layer index
  105. \return number of types
  106. \return -1 on error
  107. */
  108. int Vect_cidx_get_num_types_by_index(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[in] Map vector map
  118. \param[in] field_index layer index
  119. \param[in] type_index type index
  120. \param[out] type feature type
  121. \param[out] count number of items
  122. \return 1 OK
  123. \return 0 on error
  124. */
  125. int
  126. Vect_cidx_get_type_count_by_index(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[in] Map vector map
  139. \param[in] field layer number
  140. \param[in] 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(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[in] Map vector map
  167. \param[in] field_index layer index
  168. \param[in] 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 OK
  173. \return 0 on error
  174. */
  175. int
  176. Vect_cidx_get_cat_by_index(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[in] Map vector map
  202. \param[in] field_index layer index
  203. \param[in] cat category number
  204. \param[in] type_mask requested type
  205. \param[in] 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(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[in] Map vector map
  263. \param[in] layer layer number
  264. \param[in] type_mask type of objects to search for
  265. \param[in] cat category number
  266. \param[out] lines array of ids of found lines/points
  267. \return
  268. */
  269. void Vect_cidx_find_all(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[in] 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(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
  341. \param[in] 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. GVFILE fp;
  350. G_debug(2, "Vect_cidx_save()");
  351. check_status(Map);
  352. plus = &(Map->plus);
  353. sprintf(buf, "%s/%s", GRASS_VECT_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[in] Map vector map
  374. \param[in] 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. 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", GRASS_VECT_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@%s>"),
  397. Map->name, Map->mapset);
  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. }