main.c 27 KB

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