main.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  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. * rewrite and GEOS added by Markus Metz
  9. *
  10. * PURPOSE: Vector buffer
  11. *
  12. * COPYRIGHT: (C) 2001-2014 by the GRASS Development Team
  13. *
  14. * This program is free software under the GNU General
  15. * Public License (>=v2). Read the file COPYING that
  16. * comes with GRASS for details.
  17. *
  18. **************************************************************/
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <unistd.h>
  22. #include <math.h>
  23. #include <grass/gis.h>
  24. #include <grass/vector.h>
  25. #include <grass/dbmi.h>
  26. #include <grass/glocale.h>
  27. #include "local_proto.h"
  28. #define PI M_PI
  29. /* returns 1 if unit_tolerance is adjusted, 0 otherwise */
  30. int adjust_tolerance(double *tolerance)
  31. {
  32. double t = 0.999 * (1 - cos(PI / 8));
  33. G_debug(2, "Maximum tolerance = %f", t);
  34. if (*tolerance > t) {
  35. *tolerance = t;
  36. return 1;
  37. }
  38. return 0;
  39. }
  40. int db_CatValArray_get_value_di(dbCatValArray * cvarr, int cat, double *value)
  41. {
  42. int t;
  43. int ctype = cvarr->ctype;
  44. int ret;
  45. if (ctype == DB_C_TYPE_INT) {
  46. ret = db_CatValArray_get_value_int(cvarr, cat, &t);
  47. if (ret != DB_OK)
  48. return ret;
  49. *value = (double)t;
  50. return DB_OK;
  51. }
  52. if (ctype == DB_C_TYPE_DOUBLE) {
  53. ret = db_CatValArray_get_value_double(cvarr, cat, value);
  54. return ret;
  55. }
  56. return DB_FAILED;
  57. }
  58. int point_in_buffer(struct buf_contours *arr_bc, struct spatial_index *si,
  59. struct Map_info *Buf, double x, double y)
  60. {
  61. int i, j, ret, flag;
  62. struct bound_box bbox;
  63. static struct ilist *List = NULL;
  64. static struct line_pnts *Points = NULL;
  65. static struct line_cats *BCats = NULL;
  66. if (List == NULL)
  67. List = Vect_new_list();
  68. if (Points == NULL)
  69. Points = Vect_new_line_struct();
  70. if (BCats == NULL)
  71. BCats = Vect_new_cats_struct();
  72. /* select outer contours overlapping with centroid (x, y) */
  73. bbox.W = bbox.E = x;
  74. bbox.N = bbox.S = y;
  75. bbox.T = PORT_DOUBLE_MAX;
  76. bbox.B = -PORT_DOUBLE_MAX;
  77. Vect_spatial_index_select(si, &bbox, List);
  78. for (i = 0; i < List->n_values; i++) {
  79. Vect_read_line(Buf, Points, BCats, arr_bc[List->value[i]].outer);
  80. ret = Vect_point_in_poly(x, y, Points);
  81. if (ret == 0)
  82. continue;
  83. flag = 1;
  84. for (j = 0; j < arr_bc[List->value[i]].inner_count; j++) {
  85. if (arr_bc[List->value[i]].inner[j] < 1)
  86. continue;
  87. Vect_read_line(Buf, Points, NULL, arr_bc[List->value[i]].inner[j]);
  88. ret = Vect_point_in_poly(x, y, Points);
  89. if (ret != 0) { /* inside inner contour */
  90. flag = 0;
  91. break;
  92. }
  93. }
  94. if (flag) {
  95. /* (x,y) is inside outer contour and outside inner contours of arr_bc[i] */
  96. return 1;
  97. }
  98. }
  99. return 0;
  100. }
  101. int buffer_cats(struct buf_contours *arr_bc, struct spatial_index *si,
  102. struct Map_info *Buf, double x, double y, struct line_cats *Cats)
  103. {
  104. int i, j, ret, flag, inside;
  105. struct bound_box bbox;
  106. static struct ilist *List = NULL;
  107. static struct line_pnts *Points = NULL;
  108. static struct line_cats *BCats = NULL;
  109. if (List == NULL)
  110. List = Vect_new_list();
  111. if (Points == NULL)
  112. Points = Vect_new_line_struct();
  113. if (BCats == NULL)
  114. BCats = Vect_new_cats_struct();
  115. /* select outer contours overlapping with centroid (x, y) */
  116. bbox.W = bbox.E = x;
  117. bbox.N = bbox.S = y;
  118. bbox.T = PORT_DOUBLE_MAX;
  119. bbox.B = -PORT_DOUBLE_MAX;
  120. Vect_spatial_index_select(si, &bbox, List);
  121. Vect_reset_cats(Cats);
  122. inside = 0;
  123. for (i = 0; i < List->n_values; i++) {
  124. Vect_read_line(Buf, Points, BCats, arr_bc[List->value[i]].outer);
  125. ret = Vect_point_in_poly(x, y, Points);
  126. if (ret == 0)
  127. continue;
  128. flag = 1;
  129. for (j = 0; j < arr_bc[List->value[i]].inner_count; j++) {
  130. if (arr_bc[List->value[i]].inner[j] < 1)
  131. continue;
  132. Vect_read_line(Buf, Points, NULL, arr_bc[List->value[i]].inner[j]);
  133. ret = Vect_point_in_poly(x, y, Points);
  134. if (ret != 0) { /* inside inner contour */
  135. flag = 0;
  136. break;
  137. }
  138. }
  139. if (flag) {
  140. /* (x,y) is inside outer contour and outside inner contours of arr_bc[i] */
  141. inside = 1;
  142. for (j = 0; j < BCats->n_cats; j++)
  143. Vect_cat_set(Cats, BCats->field[j], BCats->cat[j]);
  144. }
  145. }
  146. return inside;
  147. }
  148. int main(int argc, char *argv[])
  149. {
  150. struct Map_info In, Out, Buf;
  151. struct line_pnts *Points;
  152. struct line_cats *Cats, *BCats, *CCats;
  153. struct GModule *module;
  154. struct Option *in_opt, *out_opt, *type_opt, *dista_opt, *distb_opt,
  155. *angle_opt;
  156. struct Flag *straight_flag, *nocaps_flag, *cats_flag;
  157. struct Option *tol_opt, *bufcol_opt, *scale_opt, *field_opt,
  158. *where_opt, *cats_opt;
  159. struct cat_list *cat_list = NULL;
  160. int verbose, use_geos;
  161. double da, db, dalpha, tolerance, unit_tolerance;
  162. int type;
  163. int i, ret, nareas, area, nlines, line;
  164. char *Areas, *Lines;
  165. int field;
  166. struct buf_contours *arr_bc;
  167. int arr_bc_alloc;
  168. struct buf_contours_pts arr_bc_pts;
  169. int line_id, buffers_count = 0;
  170. struct spatial_index si;
  171. struct bound_box bbox;
  172. /* Attributes if sizecol is used */
  173. int nrec, ctype;
  174. struct field_info *Fi = NULL;
  175. dbDriver *Driver;
  176. dbCatValArray cvarr;
  177. double size_val, scale;
  178. #ifdef HAVE_GEOS
  179. /* TODO: use GEOSBufferParams * */
  180. #endif
  181. module = G_define_module();
  182. G_add_keyword(_("vector"));
  183. G_add_keyword(_("buffer"));
  184. G_add_keyword(_("area"));
  185. G_add_keyword(_("circle"));
  186. G_add_keyword(_("geometry"));
  187. G_add_keyword(_("line"));
  188. G_add_keyword(_("grow"));
  189. G_add_keyword(_("shrink"));
  190. module->description =
  191. _("Creates a buffer around vector features of given type.");
  192. in_opt = G_define_standard_option(G_OPT_V_INPUT);
  193. field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL);
  194. field_opt->guisection = _("Selection");
  195. cats_opt = G_define_standard_option(G_OPT_V_CATS);
  196. cats_opt->guisection = _("Selection");
  197. where_opt = G_define_standard_option(G_OPT_DB_WHERE);
  198. where_opt->guisection = _("Selection");
  199. type_opt = G_define_standard_option(G_OPT_V_TYPE);
  200. type_opt->options = "point,line,boundary,centroid,area";
  201. type_opt->answer = "point,line,area";
  202. type_opt->guisection = _("Selection");
  203. out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
  204. dista_opt = G_define_option();
  205. dista_opt->key = "distance";
  206. dista_opt->type = TYPE_DOUBLE;
  207. dista_opt->required = NO;
  208. dista_opt->description =
  209. _("Buffer distance along major axis in map units");
  210. dista_opt->guisection = _("Distance");
  211. distb_opt = G_define_option();
  212. distb_opt->key = "minordistance";
  213. distb_opt->type = TYPE_DOUBLE;
  214. distb_opt->required = NO;
  215. distb_opt->description =
  216. _("Buffer distance along minor axis in map units");
  217. distb_opt->guisection = _("Distance");
  218. angle_opt = G_define_option();
  219. angle_opt->key = "angle";
  220. angle_opt->type = TYPE_DOUBLE;
  221. angle_opt->required = NO;
  222. angle_opt->answer = "0";
  223. angle_opt->description = _("Angle of major axis in degrees");
  224. angle_opt->guisection = _("Distance");
  225. bufcol_opt = G_define_standard_option(G_OPT_DB_COLUMN);
  226. bufcol_opt->description =
  227. _("Name of column to use for buffer distances");
  228. bufcol_opt->guisection = _("Distance");
  229. scale_opt = G_define_option();
  230. scale_opt->key = "scale";
  231. scale_opt->type = TYPE_DOUBLE;
  232. scale_opt->required = NO;
  233. scale_opt->answer = "1.0";
  234. scale_opt->description = _("Scaling factor for attribute column values");
  235. scale_opt->guisection = _("Distance");
  236. tol_opt = G_define_option();
  237. tol_opt->key = "tolerance";
  238. tol_opt->type = TYPE_DOUBLE;
  239. tol_opt->required = NO;
  240. tol_opt->description =
  241. _("Maximum distance between theoretical arc and polygon segments as multiple of buffer (default 0.01)");
  242. tol_opt->guisection = _("Distance");
  243. straight_flag = G_define_flag();
  244. straight_flag->key = 's';
  245. straight_flag->description = _("Make outside corners straight");
  246. nocaps_flag = G_define_flag();
  247. nocaps_flag->key = 'c';
  248. nocaps_flag->description = _("Do not make caps at the ends of polylines");
  249. cats_flag = G_define_flag();
  250. cats_flag->key = 't';
  251. cats_flag->description = _("Transfer categories and attributes");
  252. cats_flag->guisection = _("Attributes");
  253. G_gisinit(argv[0]);
  254. if (G_parser(argc, argv))
  255. exit(EXIT_FAILURE);
  256. verbose = G_verbose();
  257. #if !defined HAVE_GEOS
  258. use_geos = FALSE;
  259. #else
  260. use_geos = getenv("GRASS_VECTOR_BUFFER") ? FALSE : TRUE;
  261. #endif
  262. G_debug(1, "use_geos = %d", use_geos);
  263. type = Vect_option_to_types(type_opt);
  264. /* TODO: no geodesic support yet in GEOS */
  265. if (G_projection() == PROJECTION_LL)
  266. G_important_message(_("Note: In latitude-longitude coordinate system specify distances in degree unit"));
  267. if ((dista_opt->answer && bufcol_opt->answer) ||
  268. (!(dista_opt->answer || bufcol_opt->answer)))
  269. G_fatal_error(_("Select a buffer distance/minordistance/angle "
  270. "or column, but not both."));
  271. Vect_check_input_output_name(in_opt->answer, out_opt->answer, G_FATAL_EXIT);
  272. Vect_set_open_level(2); /* topology required */
  273. if (Vect_open_old2(&In, in_opt->answer, "", field_opt->answer) < 0)
  274. G_fatal_error(_("Unable to open vector map <%s>"), in_opt->answer);
  275. Vect_set_error_handler_io(&In, &Out);
  276. if (field_opt->answer)
  277. field = Vect_get_field_number(&In, field_opt->answer);
  278. else
  279. field = -1;
  280. if ((cats_opt->answer || where_opt->answer) && field == -1) {
  281. G_warning(_("Invalid layer number (%d). Parameter '%s' or '%s' specified, assuming layer '1'."),
  282. field, cats_opt->key, where_opt->key);
  283. field = 1;
  284. }
  285. cat_list = NULL;
  286. if (field > 0)
  287. cat_list = Vect_cats_set_constraint(&In, field, where_opt->answer,
  288. cats_opt->answer);
  289. if (bufcol_opt->answer && field == -1)
  290. G_fatal_error(_("The bufcol option requires a valid layer."));
  291. tolerance = 0.01;
  292. if (tol_opt->answer) {
  293. tolerance = atof(tol_opt->answer);
  294. if (tolerance <= 0)
  295. G_fatal_error(_("The tolerance must be > 0."));
  296. }
  297. if (adjust_tolerance(&tolerance))
  298. G_warning(_("The tolerance was reset to %g"), tolerance);
  299. scale = atof(scale_opt->answer);
  300. if (scale <= 0.0)
  301. G_fatal_error(_("Illegal scale value"));
  302. da = db = dalpha = unit_tolerance = 0;
  303. if (dista_opt->answer) {
  304. da = atof(dista_opt->answer);
  305. if (distb_opt->answer)
  306. db = atof(distb_opt->answer);
  307. else
  308. db = da;
  309. if (angle_opt->answer)
  310. dalpha = atof(angle_opt->answer);
  311. else
  312. dalpha = 0;
  313. unit_tolerance = fabs(tolerance * MIN(da, db));
  314. G_verbose_message(_("The tolerance in map units = %g"), unit_tolerance);
  315. if (use_geos) {
  316. if (distb_opt->answer)
  317. G_warning(_("Option '%s' is not available with GEOS buffering"),
  318. distb_opt->key);
  319. if (dalpha != 0)
  320. G_warning(_("Option '%s' is not available with GEOS buffering"),
  321. angle_opt->key);
  322. if (tol_opt->answer)
  323. G_warning(_("Option '%s' is not available with GEOS buffering"),
  324. tol_opt->key);
  325. }
  326. }
  327. if (Vect_open_new(&Out, out_opt->answer, WITHOUT_Z) < 0)
  328. G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer);
  329. Points = Vect_new_line_struct();
  330. Cats = Vect_new_cats_struct();
  331. BCats = Vect_new_cats_struct();
  332. CCats = Vect_new_cats_struct();
  333. /* open tmp vector for buffers, needed for cleaning */
  334. if (0 > Vect_open_tmp_new(&Buf, NULL, WITHOUT_Z))
  335. G_fatal_error(_("Unable to create temporary vector map"));
  336. G_set_verbose(0);
  337. Vect_build_partial(&Buf, GV_BUILD_BASE); /* switch to level 2 */
  338. G_set_verbose(verbose);
  339. /* check and load attribute column data */
  340. if (bufcol_opt->answer) {
  341. db_CatValArray_init(&cvarr);
  342. Fi = Vect_get_field(&In, field);
  343. if (Fi == NULL)
  344. G_fatal_error(_("Database connection not defined for layer %d"),
  345. field);
  346. Driver = db_start_driver_open_database(Fi->driver, Fi->database);
  347. if (Driver == NULL)
  348. G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
  349. Fi->database, Fi->driver);
  350. db_set_error_handler_driver(Driver);
  351. /* Note do not check if the column exists in the table because it may be expression */
  352. /* TODO: only select values we need instead of all in column */
  353. nrec =
  354. db_select_CatValArray(Driver, Fi->table, Fi->key,
  355. bufcol_opt->answer, NULL, &cvarr);
  356. if (nrec < 0)
  357. G_fatal_error(_("Unable to select data from table <%s>"),
  358. Fi->table);
  359. G_debug(2, "%d records selected from table", nrec);
  360. ctype = cvarr.ctype;
  361. if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE)
  362. G_fatal_error(_("Column type not supported"));
  363. db_close_database_shutdown_driver(Driver);
  364. /* Output cats/values list */
  365. for (i = 0; i < cvarr.n_values; i++) {
  366. if (ctype == DB_C_TYPE_INT) {
  367. G_debug(4, "cat = %d val = %d", cvarr.value[i].cat,
  368. cvarr.value[i].val.i);
  369. }
  370. else if (ctype == DB_C_TYPE_DOUBLE) {
  371. G_debug(4, "cat = %d val = %f", cvarr.value[i].cat,
  372. cvarr.value[i].val.d);
  373. }
  374. }
  375. }
  376. Vect_copy_head_data(&In, &Out);
  377. Vect_hist_copy(&In, &Out);
  378. Vect_hist_command(&Out);
  379. /* Create buffers' boundaries */
  380. nlines = nareas = 0;
  381. if ((type & GV_POINTS) || (type & GV_LINES))
  382. nlines = Vect_get_num_primitives(&In, type);
  383. if (type & GV_AREA)
  384. nareas = Vect_get_num_areas(&In);
  385. if (nlines + nareas == 0) {
  386. G_warning(_("No features available for buffering. "
  387. "Check type option and features available in the input vector."));
  388. exit(EXIT_SUCCESS);
  389. }
  390. /* init arr_bc */
  391. buffers_count = 1;
  392. arr_bc_alloc = nlines + nareas + 1;
  393. arr_bc = G_calloc(arr_bc_alloc, sizeof(struct buf_contours));
  394. Vect_spatial_index_init(&si, 0);
  395. #ifdef HAVE_GEOS
  396. initGEOS(G_message, G_fatal_error);
  397. /* check required version for -s/-c flag */
  398. #ifndef GEOS_3_3
  399. G_warning(_("Flags -%c/%c ignored by this version, GEOS >= 3.3 is required"),
  400. 's', 'c');
  401. #endif
  402. #endif
  403. if(!use_geos && (da < 0. || db < 0.)) {
  404. G_warning(_("Negative distances for internal buffers are not supported "
  405. "and converted to positive values."));
  406. da = fabs(da);
  407. db = fabs(db);
  408. }
  409. /* Areas */
  410. if (nareas > 0) {
  411. int centroid;
  412. G_message(_("Buffering areas..."));
  413. for (area = 1; area <= nareas; area++) {
  414. int cat;
  415. G_percent(area, nareas, 2);
  416. if (!Vect_area_alive(&In, area))
  417. continue;
  418. centroid = Vect_get_area_centroid(&In, area);
  419. if (centroid == 0)
  420. continue;
  421. Vect_read_line(&In, NULL, Cats, centroid);
  422. if (field > 0 && !Vect_cats_in_constraint(Cats, field, cat_list))
  423. continue;
  424. Vect_reset_cats(CCats);
  425. for (i = 0; i < Cats->n_cats; i++) {
  426. if (field < 0) {
  427. Vect_cat_set(CCats, Cats->field[i], Cats->cat[i]);
  428. }
  429. else if (field > 0 && Cats->field[i] == field) {
  430. if (!cat_list) {
  431. Vect_cat_set(CCats, Cats->field[i], Cats->cat[i]);
  432. }
  433. else if (Vect_cat_in_cat_list(Cats->cat[i], cat_list)) {
  434. Vect_cat_set(CCats, Cats->field[i], Cats->cat[i]);
  435. }
  436. }
  437. }
  438. if (bufcol_opt->answer) {
  439. Vect_cat_get(Cats, field, &cat);
  440. ret = db_CatValArray_get_value_di(&cvarr, cat, &size_val);
  441. if (ret != DB_OK) {
  442. G_warning(_("No record for category %d in table <%s>"),
  443. cat, Fi->table);
  444. continue;
  445. }
  446. if (size_val < 0.0) {
  447. G_warning(_("Attribute is of invalid size (%.3f) for category %d"),
  448. size_val, cat);
  449. continue;
  450. }
  451. if (size_val == 0.0)
  452. continue;
  453. da = size_val * scale;
  454. db = da;
  455. dalpha = 0;
  456. unit_tolerance = fabs(tolerance * MIN(da, db));
  457. G_debug(2, " dynamic buffer size = %.2f", da);
  458. G_debug(2, _("The tolerance in map units: %g"),
  459. unit_tolerance);
  460. }
  461. #ifdef HAVE_GEOS
  462. if (use_geos)
  463. geos_buffer(&In, &Out, &Buf, area, GV_AREA, da,
  464. &si, CCats, &arr_bc, &buffers_count, &arr_bc_alloc,
  465. straight_flag->answer, nocaps_flag->answer);
  466. #endif
  467. if (!use_geos) {
  468. Vect_area_buffer2(&In, area, da, db, dalpha,
  469. !(straight_flag->answer),
  470. !(nocaps_flag->answer), unit_tolerance,
  471. &(arr_bc_pts.oPoints),
  472. &(arr_bc_pts.iPoints),
  473. &(arr_bc_pts.inner_count));
  474. Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.oPoints, BCats);
  475. line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.oPoints, CCats);
  476. Vect_destroy_line_struct(arr_bc_pts.oPoints);
  477. /* add buffer to spatial index */
  478. Vect_get_line_box(&Buf, line_id, &bbox);
  479. Vect_spatial_index_add_item(&si, buffers_count, &bbox);
  480. arr_bc[buffers_count].outer = line_id;
  481. arr_bc[buffers_count].inner_count = arr_bc_pts.inner_count;
  482. if (arr_bc_pts.inner_count > 0) {
  483. arr_bc[buffers_count].inner = G_malloc(arr_bc_pts.inner_count * sizeof(int));
  484. for (i = 0; i < arr_bc_pts.inner_count; i++) {
  485. Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.iPoints[i], BCats);
  486. line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.iPoints[i], BCats);
  487. Vect_destroy_line_struct(arr_bc_pts.iPoints[i]);
  488. arr_bc[buffers_count].inner[i] = line_id;
  489. }
  490. G_free(arr_bc_pts.iPoints);
  491. }
  492. buffers_count++;
  493. } /* native buffer end */
  494. }
  495. }
  496. /* Lines (and Points) */
  497. if (nlines > 0) {
  498. int ltype;
  499. G_message(_("Buffering features..."));
  500. if (da < 0 || db < 0) {
  501. G_warning(_("Negative distances are only supported for areas"));
  502. da = fabs(da);
  503. db = fabs(db);
  504. }
  505. nlines = Vect_get_num_lines(&In);
  506. for (line = 1; line <= nlines; line++) {
  507. int cat;
  508. G_debug(2, "line = %d", line);
  509. G_percent(line, nlines, 2);
  510. if (!Vect_line_alive(&In, line))
  511. continue;
  512. ltype = Vect_read_line(&In, Points, Cats, line);
  513. if (!(ltype & type))
  514. continue;
  515. if (field > 0 && !Vect_cats_in_constraint(Cats, field, cat_list))
  516. continue;
  517. Vect_reset_cats(CCats);
  518. for (i = 0; i < Cats->n_cats; i++) {
  519. if (field < 0) {
  520. Vect_cat_set(CCats, Cats->field[i], Cats->cat[i]);
  521. }
  522. else if (field > 0 && Cats->field[i] == field) {
  523. if (!cat_list) {
  524. Vect_cat_set(CCats, Cats->field[i], Cats->cat[i]);
  525. }
  526. else if (Vect_cat_in_cat_list(Cats->cat[i], cat_list)) {
  527. Vect_cat_set(CCats, Cats->field[i], Cats->cat[i]);
  528. }
  529. }
  530. }
  531. if (bufcol_opt->answer) {
  532. Vect_cat_get(Cats, field, &cat);
  533. ret = db_CatValArray_get_value_di(&cvarr, cat, &size_val);
  534. if (ret != DB_OK) {
  535. G_warning(_("No record for category %d in table <%s>"),
  536. cat, Fi->table);
  537. continue;
  538. }
  539. if (size_val < 0.0) {
  540. G_warning(_("Attribute is of invalid size (%.3f) for category %d"),
  541. size_val, cat);
  542. continue;
  543. }
  544. if (size_val == 0.0)
  545. continue;
  546. da = size_val * scale;
  547. if (da < 0) {
  548. G_warning(_("Negative distances are only supported for areas"));
  549. da = fabs(da);
  550. }
  551. db = da;
  552. dalpha = 0;
  553. unit_tolerance = tolerance * MIN(da, db);
  554. G_debug(2, " dynamic buffer size = %.2f", da);
  555. G_debug(2, _("The tolerance in map units: %g"),
  556. unit_tolerance);
  557. }
  558. if (da <= 0) {
  559. G_warning(_("Distances must be positive, ignoring distance %g"), da);
  560. continue;
  561. }
  562. Vect_line_prune(Points);
  563. if (ltype & GV_POINTS || Points->n_points == 1) {
  564. if (straight_flag->answer) {
  565. arr_bc_pts.oPoints = Vect_new_line_struct();
  566. Vect_append_point(arr_bc_pts.oPoints, Points->x[0] + da, Points->y[0] + da, 0);
  567. Vect_append_point(arr_bc_pts.oPoints, Points->x[0] + da, Points->y[0] - da, 0);
  568. Vect_append_point(arr_bc_pts.oPoints, Points->x[0] - da, Points->y[0] - da, 0);
  569. Vect_append_point(arr_bc_pts.oPoints, Points->x[0] - da, Points->y[0] + da, 0);
  570. Vect_append_point(arr_bc_pts.oPoints, arr_bc_pts.oPoints->x[0], arr_bc_pts.oPoints->y[0], arr_bc_pts.oPoints->z[0]);
  571. } else {
  572. Vect_point_buffer2(Points->x[0], Points->y[0], da, db, dalpha,
  573. !(straight_flag->answer), unit_tolerance,
  574. &(arr_bc_pts.oPoints));
  575. }
  576. Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.oPoints, BCats);
  577. line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.oPoints, CCats);
  578. Vect_destroy_line_struct(arr_bc_pts.oPoints);
  579. /* add buffer to spatial index */
  580. Vect_get_line_box(&Buf, line_id, &bbox);
  581. Vect_spatial_index_add_item(&si, buffers_count, &bbox);
  582. arr_bc[buffers_count].outer = line_id;
  583. arr_bc[buffers_count].inner_count = 0;
  584. arr_bc[buffers_count].inner = NULL;
  585. buffers_count++;
  586. }
  587. else {
  588. #ifdef HAVE_GEOS
  589. if (use_geos)
  590. geos_buffer(&In, &Out, &Buf, line, type, da,
  591. &si, CCats, &arr_bc, &buffers_count, &arr_bc_alloc,
  592. straight_flag->answer, nocaps_flag->answer);
  593. #endif
  594. if (!use_geos) {
  595. Vect_line_buffer2(Points, da, db, dalpha,
  596. !(straight_flag->answer),
  597. !(nocaps_flag->answer), unit_tolerance,
  598. &(arr_bc_pts.oPoints),
  599. &(arr_bc_pts.iPoints),
  600. &(arr_bc_pts.inner_count));
  601. Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.oPoints, BCats);
  602. line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.oPoints, CCats);
  603. Vect_destroy_line_struct(arr_bc_pts.oPoints);
  604. /* add buffer to spatial index */
  605. Vect_get_line_box(&Buf, line_id, &bbox);
  606. Vect_spatial_index_add_item(&si, buffers_count, &bbox);
  607. arr_bc[buffers_count].outer = line_id;
  608. arr_bc[buffers_count].inner_count = arr_bc_pts.inner_count;
  609. if (arr_bc_pts.inner_count > 0) {
  610. arr_bc[buffers_count].inner = G_malloc(arr_bc_pts.inner_count * sizeof(int));
  611. for (i = 0; i < arr_bc_pts.inner_count; i++) {
  612. Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.iPoints[i], BCats);
  613. line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.iPoints[i], BCats);
  614. Vect_destroy_line_struct(arr_bc_pts.iPoints[i]);
  615. arr_bc[buffers_count].inner[i] = line_id;
  616. }
  617. G_free(arr_bc_pts.iPoints);
  618. }
  619. buffers_count++;
  620. } /* native buffer end */
  621. }
  622. }
  623. }
  624. #ifdef HAVE_GEOS
  625. finishGEOS();
  626. #endif
  627. G_message(_("Cleaning buffers..."));
  628. /* Break lines */
  629. G_message(_("Building parts of topology..."));
  630. Vect_build_partial(&Out, GV_BUILD_BASE);
  631. /* Warning: snapping must be done, otherwise colinear boundaries are not broken and
  632. * topology cannot be built (the same angle). But snapping distance must be very, very
  633. * small, otherwise counterclockwise boundaries can appear in areas outside the buffer.
  634. * I have done some tests on real data (projected) and threshold 1e-8 was not enough,
  635. * Snapping threshold 1e-7 seems to work. Don't increase until we find example
  636. * where it is not sufficient. RB */
  637. /* TODO: look at snapping threshold better, calculate some theoretical value to avoid
  638. * the same angles of lines at nodes, don't forget about LongLat data, probably
  639. * calculate different threshold for each map, depending on map's bounding box
  640. * and/or distance and tolerance */
  641. G_message(_("Snapping boundaries..."));
  642. Vect_snap_lines(&Out, GV_BOUNDARY, 1e-7, NULL);
  643. G_message(_("Breaking polygons..."));
  644. Vect_break_polygons(&Out, GV_BOUNDARY, NULL);
  645. G_message(_("Removing duplicates..."));
  646. Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL);
  647. do {
  648. G_message(_("Breaking boundaries..."));
  649. Vect_break_lines(&Out, GV_BOUNDARY, NULL);
  650. G_message(_("Removing duplicates..."));
  651. Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL);
  652. G_message(_("Cleaning boundaries at nodes"));
  653. } while (Vect_clean_small_angles_at_nodes(&Out, GV_BOUNDARY, NULL) > 0);
  654. /* Dangles and bridges don't seem to be necessary if snapping is small enough. */
  655. /* Still needed for larger buffer distances ? */
  656. Vect_build_partial(&Out, GV_BUILD_AREAS);
  657. G_message(_("Removing dangles..."));
  658. Vect_remove_dangles(&Out, GV_BOUNDARY, -1, NULL);
  659. G_message (_("Removing bridges..."));
  660. Vect_remove_bridges(&Out, NULL, NULL, NULL);
  661. G_message(_("Attaching islands..."));
  662. Vect_build_partial(&Out, GV_BUILD_ATTACH_ISLES);
  663. if (!cats_flag->answer) {
  664. /* Calculate new centroids for all areas */
  665. nareas = Vect_get_num_areas(&Out);
  666. Areas = (char *)G_calloc(nareas + 1, sizeof(char));
  667. G_message(_("Calculating centroids for all areas..."));
  668. G_percent(0, nareas, 2);
  669. for (area = 1; area <= nareas; area++) {
  670. double x, y;
  671. G_percent(area, nareas, 2);
  672. G_debug(3, "area = %d", area);
  673. if (!Vect_area_alive(&Out, area))
  674. continue;
  675. ret = Vect_get_point_in_area(&Out, area, &x, &y);
  676. if (ret < 0) {
  677. G_warning(_("Cannot calculate area centroid"));
  678. continue;
  679. }
  680. ret = point_in_buffer(arr_bc, &si, &Buf, x, y);
  681. if (ret) {
  682. G_debug(3, " -> in buffer");
  683. Areas[area] = 1;
  684. }
  685. }
  686. /* Make a list of boundaries to be deleted (both sides inside) */
  687. nlines = Vect_get_num_lines(&Out);
  688. G_debug(3, "nlines = %d", nlines);
  689. Lines = (char *)G_calloc(nlines + 1, sizeof(char));
  690. G_message(_("Generating list of boundaries to be deleted..."));
  691. for (line = 1; line <= nlines; line++) {
  692. int j, side[2], areas[2];
  693. G_percent(line, nlines, 2);
  694. G_debug(3, "line = %d", line);
  695. if (!Vect_line_alive(&Out, line))
  696. continue;
  697. Vect_get_line_areas(&Out, line, &side[0], &side[1]);
  698. for (j = 0; j < 2; j++) {
  699. if (side[j] == 0) { /* area/isle not build */
  700. areas[j] = 0;
  701. }
  702. else if (side[j] > 0) { /* area */
  703. areas[j] = side[j];
  704. }
  705. else { /* < 0 -> island */
  706. areas[j] = Vect_get_isle_area(&Out, abs(side[j]));
  707. }
  708. }
  709. G_debug(3, " areas = %d , %d -> Areas = %d, %d", areas[0], areas[1],
  710. Areas[areas[0]], Areas[areas[1]]);
  711. if (Areas[areas[0]] && Areas[areas[1]])
  712. Lines[line] = 1;
  713. }
  714. G_free(Areas);
  715. /* Delete boundaries */
  716. G_message(_("Deleting boundaries..."));
  717. for (line = 1; line <= nlines; line++) {
  718. G_percent(line, nlines, 2);
  719. if (!Vect_line_alive(&Out, line))
  720. continue;
  721. if (Lines[line]) {
  722. G_debug(3, " delete line %d", line);
  723. Vect_delete_line(&Out, line);
  724. }
  725. else {
  726. /* delete incorrect boundaries */
  727. int side[2];
  728. Vect_get_line_areas(&Out, line, &side[0], &side[1]);
  729. if (!side[0] && !side[1]) {
  730. G_debug(3, " delete line %d", line);
  731. Vect_delete_line(&Out, line);
  732. }
  733. }
  734. }
  735. G_free(Lines);
  736. }
  737. /* Create new centroids */
  738. Vect_reset_cats(Cats);
  739. Vect_cat_set(Cats, 1, 1);
  740. nareas = Vect_get_num_areas(&Out);
  741. G_message(_("Calculating centroids for areas..."));
  742. for (area = 1; area <= nareas; area++) {
  743. double x, y;
  744. G_percent(area, nareas, 2);
  745. G_debug(3, "area = %d", area);
  746. if (!Vect_area_alive(&Out, area))
  747. continue;
  748. ret = Vect_get_point_in_area(&Out, area, &x, &y);
  749. if (ret < 0) {
  750. G_warning(_("Unable to calculate centroid for area %d"), area);
  751. continue;
  752. }
  753. if (cats_flag->answer)
  754. ret = buffer_cats(arr_bc, &si, &Buf, x, y, Cats);
  755. else
  756. ret = point_in_buffer(arr_bc, &si, &Buf, x, y);
  757. if (ret) {
  758. Vect_reset_line(Points);
  759. Vect_append_point(Points, x, y, 0.);
  760. Vect_write_line(&Out, GV_CENTROID, Points, Cats);
  761. }
  762. }
  763. Vect_spatial_index_destroy(&si);
  764. Vect_close(&Buf);
  765. if (cats_flag->answer)
  766. Vect_copy_tables(&In, &Out, field);
  767. Vect_close(&In);
  768. Vect_build_partial(&Out, GV_BUILD_NONE);
  769. Vect_build(&Out);
  770. Vect_close(&Out);
  771. exit(EXIT_SUCCESS);
  772. }