misc.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /****************************************************************
  2. *
  3. * MODULE: v.generalize
  4. *
  5. * AUTHOR(S): Daniel Bundala, Markus Metz
  6. *
  7. * PURPOSE: miscellaneous functions of v.generalize
  8. *
  9. *
  10. * COPYRIGHT: (C) 2002-2005 by the GRASS Development Team
  11. *
  12. * This program is free software under the
  13. * GNU General Public License (>=v2).
  14. * Read the file COPYING that comes with GRASS
  15. * for details.
  16. *
  17. ****************************************************************/
  18. #include <stdlib.h>
  19. #include <grass/gis.h>
  20. #include <grass/vector.h>
  21. #include <grass/dbmi.h>
  22. #include <grass/glocale.h>
  23. #include "misc.h"
  24. int type_mask(struct Option *type_opt)
  25. {
  26. int res = 0;
  27. int i;
  28. for (i = 0; type_opt->answers[i]; i++)
  29. switch (type_opt->answers[i][0]) {
  30. case 'l':
  31. res |= GV_LINE;
  32. break;
  33. case 'b':
  34. res |= GV_BOUNDARY;
  35. break;
  36. case 'a':
  37. res |= GV_AREA;
  38. }
  39. return res;
  40. }
  41. int get_furthest(struct line_pnts *Points, int a, int b, int with_z,
  42. double *dist)
  43. {
  44. int index = a;
  45. double d = 0;
  46. int i;
  47. double x0 = Points->x[a];
  48. double x1 = Points->x[b];
  49. double y0 = Points->y[a];
  50. double y1 = Points->y[b];
  51. double z0 = Points->z[a];
  52. double z1 = Points->z[b];
  53. double px, py, pz, pdist, di;
  54. int status;
  55. for (i = a + 1; i < b; i++) {
  56. di = dig_distance2_point_to_line(Points->x[i], Points->y[i],
  57. Points->z[i], x0, y0, z0, x1, y1, z1,
  58. with_z, &px, &py, &pz, &pdist,
  59. &status);
  60. if (di > d) {
  61. d = di;
  62. index = i;
  63. }
  64. }
  65. *dist = d;
  66. return index;
  67. }
  68. /* TODO: The collection of categories is horrible in current version!
  69. * Everything repeats many times. We need some data structure
  70. * implementing set! */
  71. int copy_tables_by_cats(struct Map_info *In, struct Map_info *Out)
  72. {
  73. /* this is the (mostly) code from v.extract, it should be moved to
  74. * some vector library (probably) */
  75. int nlines, line, nfields;
  76. int ttype, ntabs = 0;
  77. struct field_info *IFi, *OFi;
  78. struct line_cats *Cats;
  79. int **ocats, *nocats, *fields;
  80. int i;
  81. /* Collect list of output cats */
  82. Cats = Vect_new_cats_struct();
  83. nfields = Vect_cidx_get_num_fields(In);
  84. ocats = (int **)G_malloc(nfields * sizeof(int *));
  85. nocats = (int *)G_malloc(nfields * sizeof(int));
  86. fields = (int *)G_malloc(nfields * sizeof(int));
  87. for (i = 0; i < nfields; i++) {
  88. nocats[i] = 0;
  89. ocats[i] =
  90. (int *)G_malloc(Vect_cidx_get_num_cats_by_index(In, i) *
  91. sizeof(int));
  92. fields[i] = Vect_cidx_get_field_number(In, i);
  93. }
  94. nlines = Vect_get_num_lines(Out);
  95. for (line = 1; line <= nlines; line++) {
  96. Vect_read_line(Out, NULL, Cats, line);
  97. for (i = 0; i < Cats->n_cats; i++) {
  98. int f = 0, j;
  99. for (j = 0; j < nfields; j++) { /* find field */
  100. if (fields[j] == Cats->field[i]) {
  101. f = j;
  102. break;
  103. }
  104. }
  105. ocats[f][nocats[f]] = Cats->cat[i];
  106. nocats[f]++;
  107. }
  108. }
  109. /* Copy tables */
  110. G_message(_("Writing attributes..."));
  111. /* Number of output tabs */
  112. for (i = 0; i < Vect_get_num_dblinks(In); i++) {
  113. int j, f = -1;
  114. IFi = Vect_get_dblink(In, i);
  115. for (j = 0; j < nfields; j++) { /* find field */
  116. if (fields[j] == IFi->number) {
  117. f = j;
  118. break;
  119. }
  120. }
  121. if (f >= 0 && nocats[f] > 0)
  122. ntabs++;
  123. }
  124. if (ntabs > 1)
  125. ttype = GV_MTABLE;
  126. else
  127. ttype = GV_1TABLE;
  128. for (i = 0; i < nfields; i++) {
  129. int ret;
  130. if (fields[i] == 0)
  131. continue;
  132. if (nocats[i] == 0)
  133. continue;
  134. /* if ( fields[i] == field && new_cat != -1 ) continue; */
  135. G_message(_("Layer %d"), fields[i]);
  136. /* Make a list of categories */
  137. IFi = Vect_get_field(In, fields[i]);
  138. if (!IFi) { /* no table */
  139. G_warning(_("Database connection not defined for layer %d"),
  140. fields[i]);
  141. continue;
  142. }
  143. OFi = Vect_default_field_info(Out, IFi->number, IFi->name, ttype);
  144. ret = db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table,
  145. OFi->driver, Vect_subst_var(OFi->database,
  146. Out),
  147. OFi->table, IFi->key, ocats[i],
  148. nocats[i]);
  149. if (ret == DB_FAILED) {
  150. G_warning(_("Unable to copy table <%s>"), IFi->table);
  151. }
  152. else {
  153. Vect_map_add_dblink(Out, OFi->number, OFi->name, OFi->table,
  154. IFi->key, OFi->database, OFi->driver);
  155. }
  156. }
  157. for (i = 0; i < nfields; i++)
  158. G_free(ocats[i]);
  159. G_free(ocats);
  160. G_free(nocats);
  161. G_free(fields);
  162. return 1;
  163. }
  164. /* check topology corruption by boundary modification
  165. * return 0 on corruption, 1 if modification is ok */
  166. int check_topo(struct Map_info *Out, int line, struct line_pnts *APoints,
  167. struct line_pnts *Points, struct line_cats *Cats)
  168. {
  169. int i, j, intersect, newline, left_old, right_old,
  170. left_new, right_new;
  171. struct bound_box box;
  172. static struct line_pnts *BPoints = NULL;
  173. static struct boxlist *List = NULL;
  174. struct line_pnts **AXLines, **BXLines;
  175. int naxlines, nbxlines;
  176. if (!BPoints)
  177. BPoints = Vect_new_line_struct();
  178. if (!List)
  179. List = Vect_new_boxlist(1);
  180. Vect_line_box(Points, &box);
  181. /* Check the modified boundary for self-intersection */
  182. AXLines = BXLines = NULL;
  183. Vect_line_intersection2(Points, NULL, &box, &box, &AXLines, &BXLines,
  184. &naxlines, &nbxlines, 0);
  185. /* Free */
  186. if (naxlines > 0) {
  187. for (j = 0; j < naxlines; j++) {
  188. Vect_destroy_line_struct(AXLines[j]);
  189. }
  190. }
  191. if (AXLines)
  192. G_free(AXLines);
  193. if (naxlines > 0)
  194. return 0;
  195. /* Check intersection of the modified boundary with other boundaries */
  196. Vect_select_lines_by_box(Out, &box, GV_BOUNDARY, List);
  197. intersect = 0;
  198. for (i = 0; i < List->n_values; i++) {
  199. int bline;
  200. bline = List->id[i];
  201. if (bline == line)
  202. continue;
  203. Vect_read_line(Out, BPoints, NULL, bline);
  204. /* Vect_line_intersection is quite slow, hopefully not so bad because only few
  205. * intersections should be found if any */
  206. AXLines = BXLines = NULL;
  207. Vect_line_intersection2(Points, BPoints, &box, &List->box[i],
  208. &AXLines, &BXLines,
  209. &naxlines, &nbxlines, 0);
  210. G_debug(4,
  211. "bline = %d intersect = %d naxlines = %d nbxlines = %d",
  212. bline, intersect, naxlines, nbxlines);
  213. /* Free */
  214. if (naxlines > 0) {
  215. for (j = 0; j < naxlines; j++) {
  216. Vect_destroy_line_struct(AXLines[j]);
  217. }
  218. }
  219. if (AXLines)
  220. G_free(AXLines);
  221. if (nbxlines > 0) {
  222. for (j = 0; j < nbxlines; j++) {
  223. Vect_destroy_line_struct(BXLines[j]);
  224. }
  225. }
  226. if (BXLines)
  227. G_free(BXLines);
  228. if (naxlines > 1 || nbxlines > 1) {
  229. intersect = 1;
  230. break;
  231. }
  232. }
  233. /* modified boundary intersects another boundary */
  234. if (intersect)
  235. return 0;
  236. /* Get centroids on the left and right side */
  237. Vect_get_line_areas(Out, line, &left_old, &right_old);
  238. if (left_old < 0)
  239. left_old = Vect_get_isle_area(Out, abs(left_old));
  240. if (left_old > 0)
  241. left_old = Vect_get_area_centroid(Out, left_old);
  242. if (right_old < 0)
  243. right_old = Vect_get_isle_area(Out, abs(right_old));
  244. if (right_old > 0)
  245. right_old = Vect_get_area_centroid(Out, right_old);
  246. /* OK, rewrite modified boundary */
  247. newline = Vect_rewrite_line(Out, line, GV_BOUNDARY, Points, Cats);
  248. /* Check position of centroids */
  249. Vect_get_line_areas(Out, newline, &left_new, &right_new);
  250. if (left_new < 0)
  251. left_new = Vect_get_isle_area(Out, abs(left_new));
  252. if (left_new > 0)
  253. left_new = Vect_get_area_centroid(Out, left_new);
  254. if (right_new < 0)
  255. right_new = Vect_get_isle_area(Out, abs(right_new));
  256. if (right_new > 0)
  257. right_new = Vect_get_area_centroid(Out, right_new);
  258. if (left_new != left_old || right_new != right_old) {
  259. G_debug(3,
  260. "The modified boundary changes attachment of centroid -> not modified");
  261. Vect_rewrite_line(Out, newline, GV_BOUNDARY, APoints, Cats);
  262. return 0;
  263. }
  264. return 1;
  265. }