cats.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. /*!
  2. * \file cats.c
  3. *
  4. * \brief Vector library - Category management
  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
  11. * GNU General Public License (>=v2).
  12. * Read the file COPYING that comes with GRASS
  13. * for details.
  14. *
  15. * \author Original author CERL, probably Dave Gerdes or Mike
  16. * Higgins
  17. * \author Update to GRASS 5.7 Radim Blazek and David D. Gray.
  18. * \author Various updates by Martin Landa <landa.martin gmail.com>
  19. */
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <grass/gis.h>
  23. #include <grass/Vect.h>
  24. #include <grass/glocale.h>
  25. static int cmp(const void *pa, const void *pb);
  26. struct line_cats *Vect__new_cats_struct(void);
  27. /*!
  28. \brief Creates and initializes line_cats structure.
  29. This structure is used for reading and writing vector cats. The
  30. library routines handle all memory allocation.
  31. \return struct line_cats *
  32. \return NULL on error
  33. */
  34. struct line_cats *Vect_new_cats_struct()
  35. {
  36. struct line_cats *p;
  37. if (NULL == (p = Vect__new_cats_struct()))
  38. G_fatal_error(_("Vect_new_cats_struct(): Out of memory"));
  39. return p;
  40. }
  41. /*!
  42. \brief Creates and initializes line_cats structure (lower level fn)
  43. This structure is used for reading and writing vector cats. The
  44. library routines handle all memory allocation.
  45. \return struct line_cats *
  46. */
  47. struct line_cats *Vect__new_cats_struct()
  48. {
  49. struct line_cats *p;
  50. p = (struct line_cats *)G_malloc(sizeof(struct line_cats));
  51. /* n_cats MUST be initialized to zero */
  52. if (p)
  53. p->n_cats = 0;
  54. if (p)
  55. p->alloc_cats = 0;
  56. return p;
  57. }
  58. /*!
  59. \brief Frees all memory associated with line_cats structure, including the struct itself.
  60. \param p line_cats structure
  61. \return 0
  62. */
  63. int Vect_destroy_cats_struct(struct line_cats *p)
  64. {
  65. if (p) { /* probably a moot test */
  66. if (p->n_cats) {
  67. G_free((void *)p->field);
  68. G_free((void *)p->cat);
  69. }
  70. G_free((void *)p);
  71. }
  72. return 0;
  73. }
  74. /*!
  75. \brief Add new field/cat to category structure if doesn't exist yet.
  76. \param[in] Cats line_cats structure
  77. \param[in] field layer number
  78. \param[in] cat category number
  79. \return number of categories
  80. \return 0 if no space for new category in structure, n_cats would be > GV_NCATS_MAX
  81. \return -1 on out of memory
  82. \return -2 if field out of range: 1 - GV_FIELD_MAX or cat out of range: 1 - GV_CAT_MAX
  83. */
  84. int Vect_cat_set(struct line_cats *Cats, int field, int cat)
  85. {
  86. register int n;
  87. /* check input values */
  88. /* compiler may warn:
  89. * comparison is always 0 due to limited range of data type
  90. * but remember that limit is set to portable data type length
  91. * and machine native size may be longer */
  92. /*
  93. if (field < 1 || field > GV_FIELD_MAX || cat < 0 || cat > GV_CAT_MAX)
  94. return (-2);
  95. */
  96. /* go through old cats and find if field/category exists */
  97. for (n = 0; n < Cats->n_cats; n++) {
  98. if (Cats->field[n] == field && Cats->cat[n] == cat)
  99. return (1);
  100. }
  101. /* field was not found so we shall append new cat */
  102. /* test if space exist */
  103. if (n >= GV_NCATS_MAX) {
  104. G_fatal_error(_("Too many categories (%d), unable to set cat %d (layer %d)"),
  105. Cats->n_cats, cat, field);
  106. }
  107. if (Cats->n_cats == Cats->alloc_cats) {
  108. if (0 > dig_alloc_cats(Cats, Cats->n_cats + 100))
  109. return (-1);
  110. }
  111. n = Cats->n_cats;
  112. Cats->field[n] = field;
  113. Cats->cat[n] = cat;
  114. Cats->n_cats++;
  115. return (1);
  116. }
  117. /*!
  118. \brief Get first found category of given field.
  119. 'cat' is set to first category found or -1 if field was not found
  120. \param[in] Cats line_cats structure
  121. \param[in] field layer number
  122. \param[in] cat pointer to variable where cat will be written
  123. \return 1 found
  124. \return 0 layer does not exist
  125. */
  126. int Vect_cat_get(struct line_cats *Cats, int field, int *cat)
  127. {
  128. register int n;
  129. /* check input value */
  130. /*
  131. if (field < 1 || field > GV_FIELD_MAX)
  132. return (0);
  133. */
  134. *cat = -1;
  135. /* go through cats and find if field exist */
  136. for (n = 0; n < Cats->n_cats; n++) {
  137. if (Cats->field[n] == field) {
  138. *cat = Cats->cat[n];
  139. return (1);
  140. }
  141. }
  142. /* field was not found */
  143. return (0);
  144. }
  145. /*!
  146. \brief Get list of categories of given field.
  147. \param Cats line_cats structure
  148. \param field layer number
  149. \param[out] cats pointer to list where cats will be written
  150. \return number of found categories
  151. \return -1 on invalid field
  152. */
  153. int Vect_field_cat_get(struct line_cats *Cats, int field, struct ilist *cats)
  154. {
  155. int n;
  156. /* reset list of categories */
  157. Vect_reset_list(cats);
  158. /* check input value */
  159. if (field < 1 || field > GV_FIELD_MAX)
  160. return -1;
  161. /* go through cats and find if field exist */
  162. for (n = 0; n < Cats->n_cats; n++) {
  163. if (Cats->field[n] != field)
  164. continue;
  165. Vect_list_append(cats, Cats->cat[n]);
  166. }
  167. return cats->n_values;
  168. }
  169. /*!
  170. \brief Delete all categories of given layer
  171. \param[in] Cats line_cats structure
  172. \param[in] field layer number
  173. \return 1 deleted
  174. \return 0 layer does not exist
  175. */
  176. int Vect_cat_del(struct line_cats *Cats, int field)
  177. {
  178. int n, m, found = 0;
  179. /* check input value */
  180. /*
  181. if (field < 1 || field > GV_FIELD_MAX)
  182. return (0);
  183. */
  184. /* go through cats and find if field exist */
  185. for (n = 0; n < Cats->n_cats; n++) {
  186. if (Cats->field[n] == field) {
  187. for (m = n; m < Cats->n_cats - 1; m++) {
  188. Cats->field[m] = Cats->field[m + 1];
  189. Cats->cat[m] = Cats->cat[m + 1];
  190. }
  191. Cats->n_cats--;
  192. found = 1;
  193. n--; /* check again this position */
  194. }
  195. }
  196. return (found);
  197. }
  198. /*!
  199. \brief Delete field/cat from line_cats structure
  200. \param[in] Cats line_cats structure
  201. \param[in] field layer number
  202. \param[in] cat category to be deleted or -1 to delete all cats of given field
  203. \return 1 deleted
  204. \return 0 field/category number does not exist
  205. */
  206. int Vect_field_cat_del(struct line_cats *Cats, int field, int cat)
  207. {
  208. register int n, m, found = 0;
  209. /* check input value */
  210. /*
  211. if (field < 1 || field > GV_FIELD_MAX)
  212. return (0);
  213. */
  214. /* go through cats and find if field exist */
  215. for (n = 0; n < Cats->n_cats; n++) {
  216. if (Cats->field[n] == field && (Cats->cat[n] == cat || cat == -1)) {
  217. for (m = n; m < Cats->n_cats - 1; m++) {
  218. Cats->field[m] = Cats->field[m + 1];
  219. Cats->cat[m] = Cats->cat[m + 1];
  220. }
  221. Cats->n_cats--;
  222. found = 1;
  223. }
  224. }
  225. return (found);
  226. }
  227. /*!
  228. \brief Reset category structure to make sure cats structure is clean to be re-used.
  229. I.e. it has no cats associated with it. Cats must have
  230. previously been created with Vect_new_cats_struct()
  231. \param[out] Cats line_cats structure
  232. \return 0
  233. */
  234. int Vect_reset_cats(struct line_cats *Cats)
  235. {
  236. Cats->n_cats = 0;
  237. return 0;
  238. }
  239. /*!
  240. \brief Allocate memory for cat_list structure.
  241. \return poiter to allocated structure
  242. \return NULL on out of memory
  243. */
  244. struct cat_list *Vect_new_cat_list()
  245. {
  246. struct cat_list *p;
  247. p = (struct cat_list *)G_malloc(sizeof(struct cat_list));
  248. /* n_ranges MUST be initialized to zero */
  249. if (p) {
  250. p->n_ranges = 0;
  251. p->alloc_ranges = 0;
  252. p->field = 0;
  253. p->min = NULL;
  254. p->max = NULL;
  255. }
  256. return p;
  257. }
  258. /*!
  259. \brief Frees allocated cat_list memory.
  260. \param[in] p line_cats structure
  261. \return 0
  262. */
  263. int Vect_destroy_cat_list(struct cat_list *p)
  264. {
  265. if (p) { /* probably a moot test */
  266. if (p->n_ranges) {
  267. G_free((void *)p->min);
  268. G_free((void *)p->max);
  269. }
  270. G_free((void *)p);
  271. }
  272. return 0;
  273. }
  274. /*!
  275. \brief Convert string of categories and cat ranges separated by commas to cat_list.
  276. Examples of string: 2,3,5-9,20. str - input string
  277. \param[in] str cat list string
  278. \param[out] list result cat_list structure
  279. \return number of errors in ranges
  280. */
  281. int Vect_str_to_cat_list(const char *str, struct cat_list *list)
  282. {
  283. int i, nr, l, err = 0;
  284. const char *s, *e;
  285. char buf[100];
  286. int min, max;
  287. G_debug(3, "Vect_str_to_cat_list(): str = %s", str);
  288. list->n_ranges = 0;
  289. l = strlen(str);
  290. /* find number of ranges */
  291. nr = 1; /* one range */
  292. for (i = 0; i < l; i++)
  293. if (str[i] == ',')
  294. nr++;
  295. /* allocate space */
  296. if (list->alloc_ranges == 0) {
  297. list->min = (int *)G_malloc(nr * sizeof(int));
  298. list->max = (int *)G_malloc(nr * sizeof(int));
  299. }
  300. else if (nr > list->alloc_ranges) {
  301. list->min = (int *)G_realloc((void *)list->min, nr * sizeof(int));
  302. list->max = (int *)G_realloc((void *)list->max, nr * sizeof(int));
  303. }
  304. /* go through string and read ranges */
  305. i = 0;
  306. s = str;
  307. while (s) {
  308. e = (char *)strchr(s, ','); /* first comma */
  309. if (e) {
  310. l = e - s;
  311. strncpy(buf, s, l);
  312. buf[l] = '\0';
  313. s = e + 1;
  314. }
  315. else {
  316. strcpy(buf, s);
  317. s = NULL;
  318. }
  319. G_debug(3, " buf = %s", buf);
  320. if (sscanf(buf, "%d-%d", &min, &max) == 2) {
  321. }
  322. else if (sscanf(buf, "%d", &min) == 1)
  323. max = min;
  324. else { /* error */
  325. G_warning(_("Unable to convert category string '%s' (from '%s') to category range"),
  326. buf, str);
  327. err++;
  328. continue;
  329. }
  330. list->min[i] = min;
  331. list->max[i] = max;
  332. i++;
  333. }
  334. list->n_ranges = i;
  335. return (err);
  336. }
  337. /*!
  338. \brief Convert ordered array of integers to cat_list structure.
  339. \param[in] vals array of integers
  340. \param[in] nvals number of values
  341. \param[out] list result cat_list structure
  342. \return number of ranges
  343. */
  344. int Vect_array_to_cat_list(int *vals, int nvals, struct cat_list *list)
  345. {
  346. int i, range;
  347. G_debug(1, "Vect_array_to_cat_list()");
  348. range = -1;
  349. for (i = 0; i < nvals; i++) {
  350. if (i == 0 || (vals[i] - list->max[range]) > 1) {
  351. range++;
  352. if (range == list->alloc_ranges) {
  353. list->alloc_ranges += 1000;
  354. list->min = (int *)G_realloc((void *)list->min,
  355. list->alloc_ranges *
  356. sizeof(int));
  357. list->max =
  358. (int *)G_realloc((void *)list->max,
  359. list->alloc_ranges * sizeof(int));
  360. }
  361. list->min[range] = vals[i];
  362. list->max[range] = vals[i];
  363. }
  364. else {
  365. list->max[range] = vals[i];
  366. }
  367. }
  368. list->n_ranges = range + 1;
  369. return (list->n_ranges);
  370. }
  371. /*!
  372. \brief Check if category number is in list.
  373. \param[in] cat category number
  374. \param[in] list cat_list structure
  375. \return TRUE if cat is in list
  376. \return FALSE if it is not
  377. */
  378. int Vect_cat_in_cat_list(int cat, struct cat_list *list)
  379. {
  380. int i;
  381. for (i = 0; i < list->n_ranges; i++)
  382. if (cat >= list->min[i] && cat <= list->max[i])
  383. return (TRUE);
  384. return (FALSE);
  385. }
  386. /*!
  387. \brief Check if category is in ordered array of integers.
  388. \param[in] cat category number
  389. \param[in] array ordered array of integers
  390. \param[in] ncats number of categories in array
  391. \return TRUE if cat is in list
  392. \return FALSE if it is not
  393. */
  394. int Vect_cat_in_array(int cat, int *array, int ncats)
  395. {
  396. int *i;
  397. i = bsearch((void *)&cat, (void *)array, (size_t) ncats,
  398. sizeof(int), cmp);
  399. if (i != NULL)
  400. return (TRUE);
  401. return (FALSE);
  402. }
  403. static int cmp(const void *pa, const void *pb)
  404. {
  405. int *p1 = (int *)pa;
  406. int *p2 = (int *)pb;
  407. if (*p1 < *p2)
  408. return -1;
  409. if (*p1 > *p2)
  410. return 1;
  411. return 0;
  412. }