main.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  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 <unistd.h>
  21. #include <math.h>
  22. #include <grass/gis.h>
  23. #include <grass/vector.h>
  24. #include <grass/dbmi.h>
  25. #include <grass/glocale.h>
  26. #define PI M_PI
  27. #ifndef MIN
  28. #define MIN(X,Y) ((X<Y)?X:Y)
  29. #endif
  30. #ifndef MAX
  31. #define MAX(X,Y) ((X>Y)?X:Y)
  32. #endif
  33. #ifdef HAVE_GEOS
  34. int geos_buffer(struct Map_info *, int, int, double,
  35. GEOSBufferParams *, struct line_pnts **,
  36. struct line_pnts ***, int *);
  37. #endif
  38. /* returns 1 if unit_tolerance is adjusted, 0 otherwise */
  39. int adjust_tolerance(double *tolerance)
  40. {
  41. double t = 0.999 * (1 - cos(PI / 8));
  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. int outer;
  71. int *inner;
  72. };
  73. struct buf_contours_pts
  74. {
  75. int inner_count;
  76. struct line_pnts *oPoints;
  77. struct line_pnts **iPoints;
  78. };
  79. int point_in_buffer(struct buf_contours *arr_bc, struct spatial_index *si,
  80. struct Map_info *Buf, double x, double y)
  81. {
  82. int i, j, ret, flag;
  83. struct bound_box bbox;
  84. static struct ilist *List = NULL;
  85. static struct line_pnts *Points = NULL;
  86. if (List == NULL)
  87. List = Vect_new_list();
  88. if (Points == NULL)
  89. Points = Vect_new_line_struct();
  90. /* select outer contours overlapping with centroid (x, y) */
  91. bbox.W = bbox.E = x;
  92. bbox.N = bbox.S = y;
  93. bbox.T = PORT_DOUBLE_MAX;
  94. bbox.B = -PORT_DOUBLE_MAX;
  95. Vect_spatial_index_select(si, &bbox, List);
  96. for (i = 0; i < List->n_values; i++) {
  97. Vect_read_line(Buf, Points, NULL, arr_bc[List->value[i]].outer);
  98. ret = Vect_point_in_poly(x, y, Points);
  99. if (ret == 0)
  100. continue;
  101. flag = 1;
  102. for (j = 0; j < arr_bc[List->value[i]].inner_count; j++) {
  103. if (arr_bc[List->value[i]].inner[j] < 1)
  104. continue;
  105. Vect_read_line(Buf, Points, NULL, arr_bc[List->value[i]].inner[j]);
  106. ret = Vect_point_in_poly(x, y, Points);
  107. if (ret != 0) { /* inside inner contour */
  108. flag = 0;
  109. break;
  110. }
  111. }
  112. if (flag) {
  113. /* (x,y) is inside outer contour and outside inner contours of arr_bc[i] */
  114. return 1;
  115. }
  116. }
  117. return 0;
  118. }
  119. int get_line_box(const struct line_pnts *Points, struct bound_box *Box)
  120. {
  121. int i;
  122. if (Points->n_points <= 0) {
  123. Box->N = 0;
  124. Box->S = 0;
  125. Box->E = 0;
  126. Box->W = 0;
  127. Box->T = 0;
  128. Box->B = 0;
  129. return 0;
  130. }
  131. Box->E = Points->x[0];
  132. Box->W = Points->x[0];
  133. Box->N = Points->y[0];
  134. Box->S = Points->y[0];
  135. Box->T = Points->z[0];
  136. Box->B = Points->z[0];
  137. for (i = 1; i < Points->n_points; i++) {
  138. if (Points->x[i] > Box->E)
  139. Box->E = Points->x[i];
  140. else if (Points->x[i] < Box->W)
  141. Box->W = Points->x[i];
  142. if (Points->y[i] > Box->N)
  143. Box->N = Points->y[i];
  144. else if (Points->y[i] < Box->S)
  145. Box->S = Points->y[i];
  146. if (Points->z[i] > Box->T)
  147. Box->T = Points->z[i];
  148. else if (Points->z[i] < Box->B)
  149. Box->B = Points->z[i];
  150. }
  151. return 1;
  152. }
  153. int main(int argc, char *argv[])
  154. {
  155. struct Map_info In, Out, Buf;
  156. struct line_pnts *Points;
  157. struct line_cats *Cats, *BCats;
  158. char bufname[GNAME_MAX];
  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;
  163. struct Option *tol_opt, *bufcol_opt, *scale_opt, *field_opt;
  164. int verbose;
  165. double da, db, dalpha, tolerance, unit_tolerance;
  166. int type;
  167. int i, ret, nareas, area, nlines, line;
  168. char *Areas, *Lines;
  169. int field;
  170. struct buf_contours *arr_bc;
  171. struct buf_contours_pts arr_bc_pts;
  172. int buffers_count = 0, line_id;
  173. struct spatial_index si;
  174. struct bound_box bbox;
  175. /* Attributes if sizecol is used */
  176. int nrec, ctype;
  177. struct field_info *Fi = NULL;
  178. dbDriver *Driver;
  179. dbCatValArray cvarr;
  180. double size_val, scale;
  181. #ifdef HAVE_GEOS
  182. GEOSBufferParams *buffer_params = NULL;
  183. #endif
  184. module = G_define_module();
  185. G_add_keyword(_("vector"));
  186. G_add_keyword(_("geometry"));
  187. G_add_keyword(_("buffer"));
  188. module->description =
  189. _("Creates a buffer around vector features of given type.");
  190. in_opt = G_define_standard_option(G_OPT_V_INPUT);
  191. field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL);
  192. field_opt->guisection = _("Selection");
  193. type_opt = G_define_standard_option(G_OPT_V_TYPE);
  194. type_opt->options = "point,line,boundary,centroid,area";
  195. type_opt->answer = "point,line,area";
  196. type_opt->guisection = _("Selection");
  197. out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
  198. dista_opt = G_define_option();
  199. dista_opt->key = "distance";
  200. dista_opt->type = TYPE_DOUBLE;
  201. dista_opt->required = NO;
  202. dista_opt->description =
  203. _("Buffer distance along major axis in map units");
  204. dista_opt->guisection = _("Distance");
  205. distb_opt = G_define_option();
  206. distb_opt->key = "minordistance";
  207. distb_opt->type = TYPE_DOUBLE;
  208. distb_opt->required = NO;
  209. distb_opt->description =
  210. _("Buffer distance along minor axis in map units");
  211. distb_opt->guisection = _("Distance");
  212. angle_opt = G_define_option();
  213. angle_opt->key = "angle";
  214. angle_opt->type = TYPE_DOUBLE;
  215. angle_opt->required = NO;
  216. angle_opt->answer = "0";
  217. angle_opt->description = _("Angle of major axis in degrees");
  218. angle_opt->guisection = _("Distance");
  219. bufcol_opt = G_define_standard_option(G_OPT_DB_COLUMN);
  220. bufcol_opt->key = "bufcolumn";
  221. bufcol_opt->description =
  222. _("Name of column to use for buffer distances");
  223. bufcol_opt->guisection = _("Distance");
  224. scale_opt = G_define_option();
  225. scale_opt->key = "scale";
  226. scale_opt->type = TYPE_DOUBLE;
  227. scale_opt->required = NO;
  228. scale_opt->answer = "1.0";
  229. scale_opt->description = _("Scaling factor for attribute column values");
  230. scale_opt->guisection = _("Distance");
  231. tol_opt = G_define_option();
  232. tol_opt->key = "tolerance";
  233. tol_opt->type = TYPE_DOUBLE;
  234. tol_opt->required = NO;
  235. tol_opt->answer = "0.01";
  236. tol_opt->description =
  237. _("Maximum distance between theoretical arc and polygon segments as multiple of buffer");
  238. tol_opt->guisection = _("Distance");
  239. straight_flag = G_define_flag();
  240. straight_flag->key = 's';
  241. straight_flag->description = _("Make outside corners straight");
  242. nocaps_flag = G_define_flag();
  243. nocaps_flag->key = 'c';
  244. nocaps_flag->description = _("Don't make caps at the ends of polylines");
  245. G_gisinit(argv[0]);
  246. if (G_parser(argc, argv))
  247. exit(EXIT_FAILURE);
  248. type = Vect_option_to_types(type_opt);
  249. if ((dista_opt->answer && bufcol_opt->answer) ||
  250. (!(dista_opt->answer || bufcol_opt->answer)))
  251. G_fatal_error(_("Select a buffer distance/minordistance/angle "
  252. "or column, but not both."));
  253. if (bufcol_opt->answer)
  254. G_warning(_("The bufcol option may contain bugs during the cleaning "
  255. "step. If you encounter problems, use the debug "
  256. "option or clean manually with v.clean tool=break; "
  257. "v.category step=0; v.extract -d type=area"));
  258. Vect_check_input_output_name(in_opt->answer, out_opt->answer, G_FATAL_EXIT);
  259. Vect_set_open_level(2); /* topology required */
  260. Vect_open_old2(&In, in_opt->answer, "", field_opt->answer);
  261. Vect_set_error_handler_io(&In, &Out);
  262. if (field_opt->answer)
  263. field = Vect_get_field_number(&In, field_opt->answer);
  264. else
  265. field = -1;
  266. if (bufcol_opt->answer && field == -1)
  267. G_fatal_error(_("The bufcol option requires a valid layer."));
  268. tolerance = atof(tol_opt->answer);
  269. if (tolerance <= 0)
  270. G_fatal_error(_("The tolerance must be > 0."));
  271. if (adjust_tolerance(&tolerance))
  272. G_warning(_("The tolerance was reset to %g"), tolerance);
  273. scale = atof(scale_opt->answer);
  274. if (scale <= 0.0)
  275. G_fatal_error("Illegal scale value");
  276. da = db = dalpha = unit_tolerance = 0;
  277. if (dista_opt->answer) {
  278. da = atof(dista_opt->answer);
  279. if (distb_opt->answer)
  280. db = atof(distb_opt->answer);
  281. else
  282. db = da;
  283. if (angle_opt->answer)
  284. dalpha = atof(angle_opt->answer);
  285. else
  286. dalpha = 0;
  287. unit_tolerance = tolerance * MIN(da, db);
  288. G_verbose_message(_("The tolerance in map units = %g"), unit_tolerance);
  289. }
  290. Vect_open_new(&Out, out_opt->answer, WITHOUT_Z);
  291. Points = Vect_new_line_struct();
  292. Cats = Vect_new_cats_struct();
  293. BCats = Vect_new_cats_struct();
  294. /* open tmp vector for buffers, needed for cleaning */
  295. sprintf(bufname, "%s_tmp_%d", out_opt->answer, getpid());
  296. if (0 > Vect_open_new(&Buf, bufname, 0)) {
  297. Vect_close(&In);
  298. Vect_close(&Out);
  299. Vect_delete(out_opt->answer);
  300. exit(EXIT_FAILURE);
  301. }
  302. Vect_build_partial(&Buf, GV_BUILD_BASE);
  303. /* check and load attribute column data */
  304. if (bufcol_opt->answer) {
  305. db_CatValArray_init(&cvarr);
  306. Fi = Vect_get_field(&In, field);
  307. if (Fi == NULL)
  308. G_fatal_error(_("Database connection not defined for layer %d"),
  309. field);
  310. Driver = db_start_driver_open_database(Fi->driver, Fi->database);
  311. if (Driver == NULL)
  312. G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
  313. Fi->database, Fi->driver);
  314. /* Note do not check if the column exists in the table because it may be expression */
  315. /* TODO: only select values we need instead of all in column */
  316. nrec =
  317. db_select_CatValArray(Driver, Fi->table, Fi->key,
  318. bufcol_opt->answer, NULL, &cvarr);
  319. if (nrec < 0)
  320. G_fatal_error(_("Unable to select data from table <%s>"),
  321. Fi->table);
  322. G_debug(2, "%d records selected from table", nrec);
  323. ctype = cvarr.ctype;
  324. if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE)
  325. G_fatal_error(_("Column type not supported"));
  326. db_close_database_shutdown_driver(Driver);
  327. /* Output cats/values list */
  328. for (i = 0; i < cvarr.n_values; i++) {
  329. if (ctype == DB_C_TYPE_INT) {
  330. G_debug(4, "cat = %d val = %d", cvarr.value[i].cat,
  331. cvarr.value[i].val.i);
  332. }
  333. else if (ctype == DB_C_TYPE_DOUBLE) {
  334. G_debug(4, "cat = %d val = %f", cvarr.value[i].cat,
  335. cvarr.value[i].val.d);
  336. }
  337. }
  338. }
  339. Vect_copy_head_data(&In, &Out);
  340. Vect_hist_copy(&In, &Out);
  341. Vect_hist_command(&Out);
  342. /* Create buffers' boundaries */
  343. nlines = nareas = 0;
  344. if ((type & GV_POINTS) || (type & GV_LINES))
  345. nlines = Vect_get_num_primitives(&In, type);
  346. if (type & GV_AREA)
  347. nareas = Vect_get_num_areas(&In);
  348. if (nlines + nareas == 0) {
  349. G_warning(_("No features available for buffering. "
  350. "Check type option and features available in the input vector."));
  351. exit(EXIT_SUCCESS);
  352. }
  353. buffers_count = 1;
  354. arr_bc = G_malloc((nlines + nareas + 1) * sizeof(struct buf_contours));
  355. Vect_spatial_index_init(&si, 0);
  356. #ifdef HAVE_GEOS
  357. initGEOS(G_message, G_fatal_error);
  358. buffer_params = GEOSBufferParams_create();
  359. GEOSBufferParams_setEndCapStyle(buffer_params, GEOSBUF_CAP_ROUND);
  360. GEOSBufferParams_setJoinStyle(buffer_params, GEOSBUF_JOIN_ROUND);
  361. #endif
  362. /* Lines (and Points) */
  363. if (nlines > 0) {
  364. int ltype;
  365. G_message(_("Buffering lines..."));
  366. nlines = Vect_get_num_lines(&In);
  367. for (line = 1; line <= nlines; line++) {
  368. int cat;
  369. G_debug(2, "line = %d", line);
  370. G_percent(line, nlines, 2);
  371. if (!Vect_line_alive(&In, line))
  372. continue;
  373. ltype = Vect_read_line(&In, Points, Cats, line);
  374. if (!(ltype & type))
  375. continue;
  376. if (field > 0 && !Vect_cat_get(Cats, field, &cat))
  377. continue;
  378. if (bufcol_opt->answer) {
  379. ret = db_CatValArray_get_value_di(&cvarr, cat, &size_val);
  380. if (ret != DB_OK) {
  381. G_warning(_("No record for category %d in table <%s>"),
  382. cat, Fi->table);
  383. continue;
  384. }
  385. if (size_val < 0.0) {
  386. G_warning(_("Attribute is of invalid size (%.3f) for category %d"),
  387. size_val, cat);
  388. continue;
  389. }
  390. if (size_val == 0.0)
  391. continue;
  392. da = size_val * scale;
  393. db = da;
  394. dalpha = 0;
  395. unit_tolerance = tolerance * MIN(da, db);
  396. G_debug(2, " dynamic buffer size = %.2f", da);
  397. G_debug(2, _("The tolerance in map units: %g"),
  398. unit_tolerance);
  399. }
  400. Vect_line_prune(Points);
  401. if (ltype & GV_POINTS || Points->n_points == 1) {
  402. Vect_point_buffer2(Points->x[0], Points->y[0], da, db, dalpha,
  403. !(straight_flag->answer), unit_tolerance,
  404. &(arr_bc_pts.oPoints));
  405. Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.oPoints, BCats);
  406. line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.oPoints, Cats);
  407. Vect_destroy_line_struct(arr_bc_pts.oPoints);
  408. /* add buffer to spatial index */
  409. Vect_get_line_box(&Buf, line_id, &bbox);
  410. Vect_spatial_index_add_item(&si, buffers_count, &bbox);
  411. arr_bc[buffers_count].outer = line_id;
  412. arr_bc[buffers_count].inner_count = 0;
  413. arr_bc[buffers_count].inner = NULL;
  414. buffers_count++;
  415. }
  416. else {
  417. #ifdef HAVE_GEOS
  418. GEOSBufferParams_setMitreLimit(buffer_params, unit_tolerance);
  419. geos_buffer(&In, line, type, da, buffer_params, &(arr_bc_pts.oPoints),
  420. &(arr_bc_pts.iPoints), &(arr_bc_pts.inner_count));
  421. #else
  422. Vect_line_buffer2(Points, da, db, dalpha,
  423. !(straight_flag->answer),
  424. !(nocaps_flag->answer), unit_tolerance,
  425. &(arr_bc_pts.oPoints),
  426. &(arr_bc_pts.iPoints),
  427. &(arr_bc_pts.inner_count));
  428. #endif
  429. Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.oPoints, BCats);
  430. line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.oPoints, Cats);
  431. Vect_destroy_line_struct(arr_bc_pts.oPoints);
  432. /* add buffer to spatial index */
  433. Vect_get_line_box(&Buf, line_id, &bbox);
  434. Vect_spatial_index_add_item(&si, buffers_count, &bbox);
  435. arr_bc[buffers_count].outer = line_id;
  436. arr_bc[buffers_count].inner_count = arr_bc_pts.inner_count;
  437. if (arr_bc_pts.inner_count > 0) {
  438. arr_bc[buffers_count].inner = G_malloc(arr_bc_pts.inner_count * sizeof(int));
  439. for (i = 0; i < arr_bc_pts.inner_count; i++) {
  440. Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.iPoints[i], BCats);
  441. line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.iPoints[i], Cats);
  442. Vect_destroy_line_struct(arr_bc_pts.iPoints[i]);
  443. /* add buffer to spatial index */
  444. Vect_get_line_box(&Buf, line_id, &bbox);
  445. Vect_spatial_index_add_item(&si, buffers_count, &bbox);
  446. arr_bc[buffers_count].inner[i] = line_id;
  447. }
  448. G_free(arr_bc_pts.iPoints);
  449. }
  450. buffers_count++;
  451. }
  452. }
  453. }
  454. /* Areas */
  455. if (nareas > 0) {
  456. int centroid;
  457. G_message(_("Buffering areas..."));
  458. for (area = 1; area <= nareas; area++) {
  459. int cat;
  460. G_percent(area, nareas, 2);
  461. if (!Vect_area_alive(&In, area))
  462. continue;
  463. centroid = Vect_get_area_centroid(&In, area);
  464. if (centroid == 0)
  465. continue;
  466. Vect_read_line(&In, NULL, Cats, centroid);
  467. if (field > 0 && !Vect_cat_get(Cats, field, &cat))
  468. continue;
  469. if (bufcol_opt->answer) {
  470. ret = db_CatValArray_get_value_di(&cvarr, cat, &size_val);
  471. if (ret != DB_OK) {
  472. G_warning(_("No record for category %d in table <%s>"),
  473. cat, Fi->table);
  474. continue;
  475. }
  476. if (size_val < 0.0) {
  477. G_warning(_("Attribute is of invalid size (%.3f) for category %d"),
  478. size_val, cat);
  479. continue;
  480. }
  481. if (size_val == 0.0)
  482. continue;
  483. da = size_val * scale;
  484. db = da;
  485. dalpha = 0;
  486. unit_tolerance = tolerance * MIN(da, db);
  487. G_debug(2, " dynamic buffer size = %.2f", da);
  488. G_debug(2, _("The tolerance in map units: %g"),
  489. unit_tolerance);
  490. }
  491. #ifdef HAVE_GEOS
  492. GEOSBufferParams_setSingleSided(buffer_params, 1);
  493. GEOSBufferParams_setMitreLimit(buffer_params, unit_tolerance);
  494. geos_buffer(&In, area, GV_AREA, da, buffer_params, &(arr_bc_pts.oPoints),
  495. &(arr_bc_pts.iPoints), &(arr_bc_pts.inner_count));
  496. #else
  497. Vect_area_buffer2(&In, area, da, db, dalpha,
  498. !(straight_flag->answer),
  499. !(nocaps_flag->answer), unit_tolerance,
  500. &(arr_bc_pts.oPoints),
  501. &(arr_bc_pts.iPoints),
  502. &(arr_bc_pts.inner_count));
  503. #endif
  504. Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.oPoints, BCats);
  505. line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.oPoints, Cats);
  506. Vect_destroy_line_struct(arr_bc_pts.oPoints);
  507. /* add buffer to spatial index */
  508. Vect_get_line_box(&Buf, line_id, &bbox);
  509. Vect_spatial_index_add_item(&si, buffers_count, &bbox);
  510. arr_bc[buffers_count].outer = line_id;
  511. arr_bc[buffers_count].inner_count = arr_bc_pts.inner_count;
  512. if (arr_bc_pts.inner_count > 0) {
  513. arr_bc[buffers_count].inner = G_malloc(arr_bc_pts.inner_count * sizeof(int));
  514. for (i = 0; i < arr_bc_pts.inner_count; i++) {
  515. Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.iPoints[i], BCats);
  516. line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.iPoints[i], Cats);
  517. Vect_destroy_line_struct(arr_bc_pts.iPoints[i]);
  518. /* add buffer to spatial index */
  519. Vect_get_line_box(&Buf, line_id, &bbox);
  520. Vect_spatial_index_add_item(&si, buffers_count, &bbox);
  521. arr_bc[buffers_count].inner[i] = line_id;
  522. }
  523. G_free(arr_bc_pts.iPoints);
  524. }
  525. buffers_count++;
  526. }
  527. }
  528. #ifdef HAVE_GEOS
  529. GEOSBufferParams_destroy(buffer_params);
  530. finishGEOS();
  531. #endif
  532. verbose = G_verbose();
  533. G_message(_("Cleaning buffers..."));
  534. /* Break lines */
  535. G_message(_("Building parts of topology..."));
  536. Vect_build_partial(&Out, GV_BUILD_BASE);
  537. G_message(_("Snapping boundaries..."));
  538. Vect_snap_lines(&Out, GV_BOUNDARY, 1e-7, NULL);
  539. G_message(_("Breaking polygons..."));
  540. Vect_break_polygons(&Out, GV_BOUNDARY, NULL);
  541. G_message(_("Removing duplicates..."));
  542. Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL);
  543. do {
  544. G_message(_("Breaking boundaries..."));
  545. Vect_break_lines(&Out, GV_BOUNDARY, NULL);
  546. G_message(_("Removing duplicates..."));
  547. Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL);
  548. G_message(_("Cleaning boundaries at nodes"));
  549. } while (Vect_clean_small_angles_at_nodes(&Out, GV_BOUNDARY, NULL) > 0);
  550. /* Dangles and bridges don't seem to be necessary if snapping is small enough. */
  551. /* Still needed for larger buffer distances ? */
  552. /*
  553. G_message(_("Removing dangles..."));
  554. Vect_remove_dangles(&Out, GV_BOUNDARY, -1, NULL);
  555. G_message (_("Removing bridges..."));
  556. Vect_remove_bridges(&Out, NULL);
  557. */
  558. G_message(_("Attaching islands..."));
  559. Vect_build_partial(&Out, GV_BUILD_ATTACH_ISLES);
  560. /* Calculate new centroids for all areas */
  561. nareas = Vect_get_num_areas(&Out);
  562. Areas = (char *)G_calloc(nareas + 1, sizeof(char));
  563. G_message(_("Calculating centroids for areas..."));
  564. G_percent(0, nareas, 2);
  565. for (area = 1; area <= nareas; area++) {
  566. double x, y;
  567. G_percent(area, nareas, 2);
  568. G_debug(3, "area = %d", area);
  569. if (!Vect_area_alive(&Out, area))
  570. continue;
  571. ret = Vect_get_point_in_area(&Out, area, &x, &y);
  572. if (ret < 0) {
  573. G_warning(_("Cannot calculate area centroid"));
  574. continue;
  575. }
  576. ret = point_in_buffer(arr_bc, &si, &Buf, x, y);
  577. if (ret) {
  578. G_debug(3, " -> in buffer");
  579. Areas[area] = 1;
  580. }
  581. }
  582. /* Make a list of boundaries to be deleted (both sides inside) */
  583. nlines = Vect_get_num_lines(&Out);
  584. G_debug(3, "nlines = %d", nlines);
  585. Lines = (char *)G_calloc(nlines + 1, sizeof(char));
  586. G_message(_("Generating list of boundaries to be deleted..."));
  587. for (line = 1; line <= nlines; line++) {
  588. int j, side[2], areas[2];
  589. G_percent(line, nlines, 2);
  590. G_debug(3, "line = %d", line);
  591. if (!Vect_line_alive(&Out, line))
  592. continue;
  593. Vect_get_line_areas(&Out, line, &side[0], &side[1]);
  594. for (j = 0; j < 2; j++) {
  595. if (side[j] == 0) { /* area/isle not build */
  596. areas[j] = 0;
  597. }
  598. else if (side[j] > 0) { /* area */
  599. areas[j] = side[j];
  600. }
  601. else { /* < 0 -> island */
  602. areas[j] = Vect_get_isle_area(&Out, abs(side[j]));
  603. }
  604. }
  605. G_debug(3, " areas = %d , %d -> Areas = %d, %d", areas[0], areas[1],
  606. Areas[areas[0]], Areas[areas[1]]);
  607. if (Areas[areas[0]] && Areas[areas[1]])
  608. Lines[line] = 1;
  609. }
  610. G_free(Areas);
  611. /* Delete boundaries */
  612. G_message(_("Deleting boundaries..."));
  613. for (line = 1; line <= nlines; line++) {
  614. G_percent(line, nlines, 2);
  615. if (!Vect_line_alive(&Out, line))
  616. continue;
  617. if (Lines[line]) {
  618. G_debug(3, " delete line %d", line);
  619. Vect_delete_line(&Out, line);
  620. }
  621. else {
  622. /* delete incorrect boundaries */
  623. int side[2];
  624. Vect_get_line_areas(&Out, line, &side[0], &side[1]);
  625. if (!side[0] && !side[1])
  626. Vect_delete_line(&Out, line);
  627. }
  628. }
  629. G_free(Lines);
  630. /* Create new centroids */
  631. Vect_reset_cats(Cats);
  632. Vect_cat_set(Cats, 1, 1);
  633. nareas = Vect_get_num_areas(&Out);
  634. G_message(_("Calculating centroids for areas..."));
  635. for (area = 1; area <= nareas; area++) {
  636. double x, y;
  637. G_percent(area, nareas, 2);
  638. G_debug(3, "area = %d", area);
  639. if (!Vect_area_alive(&Out, area))
  640. continue;
  641. ret = Vect_get_point_in_area(&Out, area, &x, &y);
  642. if (ret < 0) {
  643. G_warning(_("Cannot calculate area centroid"));
  644. continue;
  645. }
  646. ret = point_in_buffer(arr_bc, &si, &Buf, x, y);
  647. if (ret) {
  648. Vect_reset_line(Points);
  649. Vect_append_point(Points, x, y, 0.);
  650. Vect_write_line(&Out, GV_CENTROID, Points, Cats);
  651. }
  652. }
  653. /* free arr_bc[] */
  654. /* will only slow down the module
  655. for (i = 0; i < buffers_count; i++) {
  656. Vect_destroy_line_struct(arr_bc[i].oPoints);
  657. for (j = 0; j < arr_bc[i].inner_count; j++)
  658. Vect_destroy_line_struct(arr_bc[i].iPoints[j]);
  659. G_free(arr_bc[i].iPoints);
  660. } */
  661. Vect_spatial_index_destroy(&si);
  662. Vect_close(&Buf);
  663. Vect_delete(bufname);
  664. G_set_verbose(verbose);
  665. Vect_close(&In);
  666. Vect_build_partial(&Out, GV_BUILD_NONE);
  667. Vect_build(&Out);
  668. Vect_close(&Out);
  669. exit(EXIT_SUCCESS);
  670. }