main.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. /****************************************************************
  2. *
  3. * MODULE: v.buffer
  4. *
  5. * AUTHOR(S): Radim Blazek
  6. * Upgraded by Rosen Matev (Google Summer of Code 2008)
  7. * OGR support by Martin Landa <landa.martin gmail.com> (2009)
  8. *
  9. * PURPOSE: Vector buffer
  10. *
  11. * COPYRIGHT: (C) 2001-2009 by the GRASS Development Team
  12. *
  13. * This program is free software under the GNU General
  14. * Public License (>=v2). Read the file COPYING that
  15. * comes with GRASS for details.
  16. *
  17. **************************************************************/
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <grass/gis.h>
  21. #include <grass/vector.h>
  22. #include <grass/dbmi.h>
  23. #include <grass/glocale.h>
  24. #define PI M_PI
  25. #ifndef MIN
  26. #define MIN(X,Y) ((X<Y)?X:Y)
  27. #endif
  28. #ifndef MAX
  29. #define MAX(X,Y) ((X>Y)?X:Y)
  30. #endif
  31. void stop(struct Map_info *In, struct Map_info *Out)
  32. {
  33. Vect_close(In);
  34. Vect_build_partial(Out, GV_BUILD_NONE);
  35. Vect_build(Out);
  36. Vect_close(Out);
  37. }
  38. /* returns 1 if unit_tolerance is adjusted, 0 otherwise */
  39. int adjust_tolerance(double *tolerance)
  40. {
  41. double t = 0.999 * (1 - cos(2 * PI / 8 / 2));
  42. G_debug(2, "Maximum tolerance = %f", t);
  43. if (*tolerance > t) {
  44. *tolerance = t;
  45. return 1;
  46. }
  47. return 0;
  48. }
  49. int db_CatValArray_get_value_di(dbCatValArray * cvarr, int cat, double *value)
  50. {
  51. int t;
  52. int ctype = cvarr->ctype;
  53. int ret;
  54. if (ctype == DB_C_TYPE_INT) {
  55. ret = db_CatValArray_get_value_int(cvarr, cat, &t);
  56. if (ret != DB_OK)
  57. return ret;
  58. *value = (double)t;
  59. return DB_OK;
  60. }
  61. if (ctype == DB_C_TYPE_DOUBLE) {
  62. ret = db_CatValArray_get_value_double(cvarr, cat, value);
  63. return ret;
  64. }
  65. return DB_FAILED;
  66. }
  67. struct buf_contours
  68. {
  69. int inner_count;
  70. struct line_pnts *oPoints;
  71. struct line_pnts **iPoints;
  72. };
  73. int point_in_buffer(struct buf_contours *arr_bc, int buffers_count,
  74. double x, double y)
  75. {
  76. int i, j, ret, flag;
  77. for (i = 0; i < buffers_count; i++) {
  78. ret = Vect_point_in_poly(x, y, arr_bc[i].oPoints);
  79. if (ret == 0)
  80. continue;
  81. flag = 1;
  82. for (j = 0; j < arr_bc[i].inner_count; j++) {
  83. ret = Vect_point_in_poly(x, y, arr_bc[i].iPoints[j]);
  84. if (ret != 0) { /* inside inner contour */
  85. flag = 0;
  86. break;
  87. }
  88. }
  89. if (flag) {
  90. /* (x,y) is inside outer contour and outside inner contours of arr_bc[i] */
  91. return 1;
  92. }
  93. }
  94. return 0;
  95. }
  96. int main(int argc, char *argv[])
  97. {
  98. struct Map_info In, Out;
  99. struct line_pnts *Points;
  100. struct line_cats *Cats, *BCats;
  101. struct GModule *module;
  102. struct Option *in_opt, *out_opt, *type_opt, *dista_opt, *distb_opt,
  103. *angle_opt;
  104. struct Flag *straight_flag, *nocaps_flag;
  105. struct Option *tol_opt, *bufcol_opt, *scale_opt, *field_opt;
  106. int verbose;
  107. double da, db, dalpha, tolerance, unit_tolerance;
  108. int type;
  109. int i, j, ret, nareas, area, nlines, line;
  110. char *Areas, *Lines;
  111. int field;
  112. struct buf_contours *arr_bc;
  113. int buffers_count;
  114. /* Attributes if sizecol is used */
  115. int nrec, ctype;
  116. struct field_info *Fi;
  117. dbDriver *Driver;
  118. dbCatValArray cvarr;
  119. double size_val, scale;
  120. module = G_define_module();
  121. G_add_keyword(_("vector"));
  122. G_add_keyword(_("geometry"));
  123. G_add_keyword(_("buffer"));
  124. module->description =
  125. _("Creates a buffer around vector features of given type.");
  126. in_opt = G_define_standard_option(G_OPT_V_INPUT);
  127. field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL);
  128. field_opt->guisection = _("Selection");
  129. type_opt = G_define_standard_option(G_OPT_V_TYPE);
  130. type_opt->options = "point,line,boundary,centroid,area";
  131. type_opt->answer = "point,line,area";
  132. type_opt->guisection = _("Selection");
  133. out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
  134. dista_opt = G_define_option();
  135. dista_opt->key = "distance";
  136. dista_opt->type = TYPE_DOUBLE;
  137. dista_opt->required = NO;
  138. dista_opt->description =
  139. _("Buffer distance along major axis in map units");
  140. dista_opt->guisection = _("Distance");
  141. distb_opt = G_define_option();
  142. distb_opt->key = "minordistance";
  143. distb_opt->type = TYPE_DOUBLE;
  144. distb_opt->required = NO;
  145. distb_opt->description =
  146. _("Buffer distance along minor axis in map units");
  147. distb_opt->guisection = _("Distance");
  148. angle_opt = G_define_option();
  149. angle_opt->key = "angle";
  150. angle_opt->type = TYPE_DOUBLE;
  151. angle_opt->required = NO;
  152. angle_opt->answer = "0";
  153. angle_opt->description = _("Angle of major axis in degrees");
  154. angle_opt->guisection = _("Distance");
  155. bufcol_opt = G_define_standard_option(G_OPT_DB_COLUMN);
  156. bufcol_opt->key = "bufcolumn";
  157. bufcol_opt->description =
  158. _("Name of column to use for buffer distances");
  159. bufcol_opt->guisection = _("Distance");
  160. scale_opt = G_define_option();
  161. scale_opt->key = "scale";
  162. scale_opt->type = TYPE_DOUBLE;
  163. scale_opt->required = NO;
  164. scale_opt->answer = "1.0";
  165. scale_opt->description = _("Scaling factor for attribute column values");
  166. scale_opt->guisection = _("Distance");
  167. tol_opt = G_define_option();
  168. tol_opt->key = "tolerance";
  169. tol_opt->type = TYPE_DOUBLE;
  170. tol_opt->required = NO;
  171. tol_opt->answer = "0.01";
  172. tol_opt->description =
  173. _("Maximum distance between theoretical arc and polygon segments as multiple of buffer");
  174. tol_opt->guisection = _("Distance");
  175. straight_flag = G_define_flag();
  176. straight_flag->key = 's';
  177. straight_flag->description = _("Make outside corners straight");
  178. nocaps_flag = G_define_flag();
  179. nocaps_flag->key = 'c';
  180. nocaps_flag->description = _("Don't make caps at the ends of polylines");
  181. G_gisinit(argv[0]);
  182. if (G_parser(argc, argv))
  183. exit(EXIT_FAILURE);
  184. type = Vect_option_to_types(type_opt);
  185. if ((dista_opt->answer && bufcol_opt->answer) ||
  186. (!(dista_opt->answer || bufcol_opt->answer)))
  187. G_fatal_error(_("Select a buffer distance/minordistance/angle "
  188. "or column, but not both."));
  189. if (bufcol_opt->answer)
  190. G_warning(_("The bufcol option may contain bugs during the cleaning "
  191. "step. If you encounter problems, use the debug "
  192. "option or clean manually with v.clean tool=break; "
  193. "v.category step=0; v.extract -d type=area"));
  194. tolerance = atof(tol_opt->answer);
  195. if (adjust_tolerance(&tolerance))
  196. G_warning(_("The tolerance was reset to %g"), tolerance);
  197. scale = atof(scale_opt->answer);
  198. if (scale <= 0.0)
  199. G_fatal_error("Illegal scale value");
  200. if (dista_opt->answer) {
  201. da = atof(dista_opt->answer);
  202. if (distb_opt->answer)
  203. db = atof(distb_opt->answer);
  204. else
  205. db = da;
  206. if (angle_opt->answer)
  207. dalpha = atof(angle_opt->answer);
  208. else
  209. dalpha = 0;
  210. unit_tolerance = tolerance * MIN(da, db);
  211. G_verbose_message(_("The tolerance in map units = %g"), unit_tolerance);
  212. }
  213. Vect_check_input_output_name(in_opt->answer, out_opt->answer,
  214. GV_FATAL_EXIT);
  215. Points = Vect_new_line_struct();
  216. Cats = Vect_new_cats_struct();
  217. BCats = Vect_new_cats_struct();
  218. Vect_set_open_level(2); /* topology required */
  219. if (1 > Vect_open_old2(&In, in_opt->answer, "", field_opt->answer))
  220. G_fatal_error(_("Unable to open vector map <%s>"), in_opt->answer);
  221. field = Vect_get_field_number(&In, field_opt->answer);
  222. if (0 > Vect_open_new(&Out, out_opt->answer, WITHOUT_Z)) {
  223. Vect_close(&In);
  224. G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer);
  225. }
  226. /* check and load attribute column data */
  227. if (bufcol_opt->answer) {
  228. db_CatValArray_init(&cvarr);
  229. Fi = Vect_get_field(&In, field);
  230. if (Fi == NULL)
  231. G_fatal_error(_("Database connection not defined for layer %d"),
  232. field);
  233. Driver = db_start_driver_open_database(Fi->driver, Fi->database);
  234. if (Driver == NULL)
  235. G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
  236. Fi->database, Fi->driver);
  237. /* Note do not check if the column exists in the table because it may be expression */
  238. /* TODO: only select values we need instead of all in column */
  239. nrec =
  240. db_select_CatValArray(Driver, Fi->table, Fi->key,
  241. bufcol_opt->answer, NULL, &cvarr);
  242. if (nrec < 0)
  243. G_fatal_error(_("Unable to select data from table <%s>"),
  244. Fi->table);
  245. G_debug(2, "%d records selected from table", nrec);
  246. ctype = cvarr.ctype;
  247. if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE)
  248. G_fatal_error(_("Column type not supported"));
  249. db_close_database_shutdown_driver(Driver);
  250. /* Output cats/values list */
  251. for (i = 0; i < cvarr.n_values; i++) {
  252. if (ctype == DB_C_TYPE_INT) {
  253. G_debug(4, "cat = %d val = %d", cvarr.value[i].cat,
  254. cvarr.value[i].val.i);
  255. }
  256. else if (ctype == DB_C_TYPE_DOUBLE) {
  257. G_debug(4, "cat = %d val = %f", cvarr.value[i].cat,
  258. cvarr.value[i].val.d);
  259. }
  260. }
  261. }
  262. Vect_copy_head_data(&In, &Out);
  263. Vect_hist_copy(&In, &Out);
  264. Vect_hist_command(&Out);
  265. /* Create buffers' boundaries */
  266. nlines = Vect_get_num_lines(&In);
  267. nareas = Vect_get_num_areas(&In);
  268. /* TODO: don't allocate so much space */
  269. buffers_count = 0;
  270. arr_bc = G_malloc((nlines + nareas) * sizeof(struct buf_contours));
  271. /* Lines (and Points) */
  272. if ((type & GV_POINTS) || (type & GV_LINES)) {
  273. int ltype;
  274. if (nlines > 0)
  275. G_message(_("Buffering features..."));
  276. for (line = 1; line <= nlines; line++) {
  277. int cat;
  278. G_debug(2, "line = %d", line);
  279. G_percent(line, nlines, 2);
  280. ltype = Vect_read_line(&In, Points, Cats, line);
  281. if (!(ltype & type))
  282. continue;
  283. if (field != -1 && !Vect_cat_get(Cats, field, &cat))
  284. continue;
  285. if (bufcol_opt->answer) {
  286. ret = db_CatValArray_get_value_di(&cvarr, cat, &size_val);
  287. if (ret != DB_OK) {
  288. G_warning(_("No record for category %d in table <%s>"),
  289. cat, Fi->table);
  290. continue;
  291. }
  292. if (size_val < 0.0) {
  293. G_warning(_("Attribute is of invalid size (%.3f) for category %d"),
  294. size_val, cat);
  295. continue;
  296. }
  297. if (size_val == 0.0)
  298. continue;
  299. da = size_val * scale;
  300. db = da;
  301. dalpha = 0;
  302. unit_tolerance = tolerance * MIN(da, db);
  303. G_debug(2, " dynamic buffer size = %.2f", da);
  304. G_debug(2, _("The tolerance in map units: %g"),
  305. unit_tolerance);
  306. }
  307. if (ltype & GV_POINTS) {
  308. Vect_point_buffer2(Points->x[0], Points->y[0], da, db, dalpha,
  309. !(straight_flag->answer), unit_tolerance,
  310. &(arr_bc[buffers_count].oPoints));
  311. arr_bc[buffers_count].iPoints = NULL;
  312. arr_bc[buffers_count].inner_count = 0;
  313. buffers_count++;
  314. }
  315. else {
  316. Vect_line_buffer2(Points, da, db, dalpha,
  317. !(straight_flag->answer),
  318. !(nocaps_flag->answer), unit_tolerance,
  319. &(arr_bc[buffers_count].oPoints),
  320. &(arr_bc[buffers_count].iPoints),
  321. &(arr_bc[buffers_count].inner_count));
  322. buffers_count++;
  323. }
  324. }
  325. }
  326. /* Areas */
  327. if (type & GV_AREA) {
  328. int centroid;
  329. if (nareas > 0)
  330. G_message(_("Buffering areas..."));
  331. for (area = 1; area <= nareas; area++) {
  332. int cat;
  333. G_percent(area, nareas, 2);
  334. centroid = Vect_get_area_centroid(&In, area);
  335. if (centroid == 0)
  336. continue;
  337. Vect_read_line(&In, NULL, Cats, centroid);
  338. if (field > 0 && !Vect_cat_get(Cats, field, &cat))
  339. continue;
  340. if (bufcol_opt->answer) {
  341. ret = db_CatValArray_get_value_di(&cvarr, cat, &size_val);
  342. if (ret != DB_OK) {
  343. G_warning(_("No record for category %d in table <%s>"),
  344. cat, Fi->table);
  345. continue;
  346. }
  347. if (size_val < 0.0) {
  348. G_warning(_("Attribute is of invalid size (%.3f) for category %d"),
  349. size_val, cat);
  350. continue;
  351. }
  352. if (size_val == 0.0)
  353. continue;
  354. da = size_val * scale;
  355. db = da;
  356. dalpha = 0;
  357. unit_tolerance = tolerance * MIN(da, db);
  358. G_debug(2, " dynamic buffer size = %.2f", da);
  359. G_debug(2, _("The tolerance in map units: %g"),
  360. unit_tolerance);
  361. }
  362. Vect_area_buffer2(&In, area, da, db, dalpha,
  363. !(straight_flag->answer),
  364. !(nocaps_flag->answer), unit_tolerance,
  365. &(arr_bc[buffers_count].oPoints),
  366. &(arr_bc[buffers_count].iPoints),
  367. &(arr_bc[buffers_count].inner_count));
  368. buffers_count++;
  369. }
  370. }
  371. /* write all buffer contours */
  372. G_message(_("Writting buffers..."));
  373. for (i = 0; i < buffers_count; i++) {
  374. G_percent(i, buffers_count, 2);
  375. Vect_write_line(&Out, GV_BOUNDARY, arr_bc[i].oPoints, BCats);
  376. for (j = 0; j < arr_bc[i].inner_count; j++)
  377. Vect_write_line(&Out, GV_BOUNDARY, arr_bc[i].iPoints[j], BCats);
  378. }
  379. G_percent(1, 1, 1);
  380. verbose = G_verbose();
  381. if (verbose < G_verbose_max()) {
  382. G_message(_("Cleaning buffers..."));
  383. G_set_verbose(0);
  384. }
  385. /* Break lines */
  386. G_message(_("Building parts of topology..."));
  387. Vect_build_partial(&Out, GV_BUILD_BASE);
  388. G_message(_("Snapping boundaries..."));
  389. Vect_snap_lines(&Out, GV_BOUNDARY, 1e-7, NULL);
  390. G_message(_("Breaking boundaries..."));
  391. Vect_break_lines(&Out, GV_BOUNDARY, NULL);
  392. G_message(_("Removing duplicates..."));
  393. Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL);
  394. /* Dangles and bridges don't seem to be necessary if snapping is small enough. */
  395. /*
  396. G_message ( "Removing dangles..." );
  397. Vect_remove_dangles ( &Out, GV_BOUNDARY, -1, NULL, stderr );
  398. G_message ( "Removing bridges..." );
  399. Vect_remove_bridges ( &Out, NULL, stderr );
  400. */
  401. G_message(_("Attaching islands..."));
  402. Vect_build_partial(&Out, GV_BUILD_ATTACH_ISLES);
  403. /* Calculate new centroids for all areas */
  404. nareas = Vect_get_num_areas(&Out);
  405. Areas = (char *)G_calloc(nareas + 1, sizeof(char));
  406. G_message(_("Calculating centroids for areas..."));
  407. for (area = 1; area <= nareas; area++) {
  408. double x, y;
  409. G_percent(area, nareas, 2);
  410. G_debug(3, "area = %d", area);
  411. if (!Vect_area_alive(&Out, area))
  412. continue;
  413. ret = Vect_get_point_in_area(&Out, area, &x, &y);
  414. if (ret < 0) {
  415. G_warning(_("Cannot calculate area centroid"));
  416. continue;
  417. }
  418. ret = point_in_buffer(arr_bc, buffers_count, x, y);
  419. if (ret) {
  420. G_debug(3, " -> in buffer");
  421. Areas[area] = 1;
  422. }
  423. }
  424. /* Make a list of boundaries to be deleted (both sides inside) */
  425. nlines = Vect_get_num_lines(&Out);
  426. G_debug(3, "nlines = %d", nlines);
  427. Lines = (char *)G_calloc(nlines + 1, sizeof(char));
  428. G_message(_("Generating list of boundaries to be deleted..."));
  429. for (line = 1; line <= nlines; line++) {
  430. G_percent(line, nlines, 2);
  431. int j, side[2], areas[2];
  432. G_debug(3, "line = %d", line);
  433. if (!Vect_line_alive(&Out, line))
  434. continue;
  435. Vect_get_line_areas(&Out, line, &side[0], &side[1]);
  436. for (j = 0; j < 2; j++) {
  437. if (side[j] == 0) { /* area/isle not build */
  438. areas[j] = 0;
  439. }
  440. else if (side[j] > 0) { /* area */
  441. areas[j] = side[j];
  442. }
  443. else { /* < 0 -> island */
  444. areas[j] = Vect_get_isle_area(&Out, abs(side[j]));
  445. }
  446. }
  447. G_debug(3, " areas = %d , %d -> Areas = %d, %d", areas[0], areas[1],
  448. Areas[areas[0]], Areas[areas[1]]);
  449. if (Areas[areas[0]] && Areas[areas[1]])
  450. Lines[line] = 1;
  451. }
  452. G_free(Areas);
  453. /* Delete boundaries */
  454. G_message(_("Deleting boundaries..."));
  455. for (line = 1; line <= nlines; line++) {
  456. G_percent(line, nlines, 2);
  457. if (Lines[line]) {
  458. G_debug(3, " delete line %d", line);
  459. Vect_delete_line(&Out, line);
  460. }
  461. }
  462. G_free(Lines);
  463. /* Create new centroids */
  464. Vect_reset_cats(Cats);
  465. Vect_cat_set(Cats, 1, 1);
  466. nareas = Vect_get_num_areas(&Out);
  467. G_message(_("Calculating centroids for areas..."));
  468. for (area = 1; area <= nareas; area++) {
  469. G_percent(area, nareas, 2);
  470. double x, y;
  471. G_debug(3, "area = %d", area);
  472. if (!Vect_area_alive(&Out, area))
  473. continue;
  474. ret = Vect_get_point_in_area(&Out, area, &x, &y);
  475. if (ret < 0) {
  476. G_warning(_("Cannot calculate area centroid"));
  477. continue;
  478. }
  479. ret = point_in_buffer(arr_bc, buffers_count, x, y);
  480. if (ret) {
  481. Vect_reset_line(Points);
  482. Vect_append_point(Points, x, y, 0.);
  483. Vect_write_line(&Out, GV_CENTROID, Points, Cats);
  484. }
  485. }
  486. /* free arr_bc[] */
  487. /* will only slow down the module
  488. for (i = 0; i < buffers_count; i++) {
  489. Vect_destroy_line_struct(arr_bc[i].oPoints);
  490. for (j = 0; j < arr_bc[i].inner_count; j++)
  491. Vect_destroy_line_struct(arr_bc[i].iPoints[j]);
  492. G_free(arr_bc[i].iPoints);
  493. } */
  494. G_message(_("Attaching centroids..."));
  495. Vect_build_partial(&Out, GV_BUILD_CENTROIDS);
  496. G_set_verbose(verbose);
  497. stop(&In, &Out);
  498. exit(EXIT_SUCCESS);
  499. }