main.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. /****************************************************************
  2. *
  3. * MODULE: v.buffer
  4. *
  5. * AUTHOR(S): Radim Blazek
  6. *
  7. * PURPOSE: Vector buffer
  8. *
  9. * COPYRIGHT: (C) 2001 by the GRASS Development Team
  10. *
  11. * This program is free software under the
  12. * GNU General Public License (>=v2).
  13. * Read the file COPYING that comes with GRASS
  14. * for details.
  15. *
  16. **************************************************************/
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <grass/gis.h>
  20. #include <grass/Vect.h>
  21. #include <grass/dbmi.h>
  22. #include <grass/glocale.h>
  23. #define DEBUG_NONE 0
  24. #define DEBUG_BUFFER 1
  25. #define DEBUG_CLEAN 2
  26. #define PI M_PI
  27. /* TODO: look at RET value and use, is it OK? */
  28. #define RET 0.000000001 /* Representation error tolerance */
  29. /* returns shortest distance to nearest input feature within the buffer
  30. * or a number greater than buffer (2*buffer) if not found */
  31. double input_distance(struct Map_info *In, int type, double buffer, double x,
  32. double y)
  33. {
  34. int i;
  35. static struct ilist *List = NULL;
  36. static struct line_pnts *Points = NULL;
  37. double current_distance;
  38. BOUND_BOX box;
  39. if (List == NULL)
  40. List = Vect_new_list();
  41. else
  42. Vect_reset_list(List);
  43. if (Points == NULL)
  44. Points = Vect_new_line_struct();
  45. /* Inside area ? */
  46. if (type & GV_AREA) {
  47. int area, centroid;
  48. /* inside */
  49. area = Vect_find_area(In, x, y);
  50. centroid = 0;
  51. if (area)
  52. centroid = Vect_get_area_centroid(In, area);
  53. G_debug(3, " area = %d centroid = %d", area, centroid);
  54. if (centroid)
  55. return 0.0;
  56. }
  57. /* ouside area, within buffer? */
  58. /* The centroid is in buffer if at least one point/line/boundary is in buffer distance */
  59. box.E = x + buffer;
  60. box.W = x - buffer;
  61. box.N = y + buffer;
  62. box.S = y - buffer;
  63. box.T = PORT_DOUBLE_MAX;
  64. box.B = -PORT_DOUBLE_MAX;
  65. Vect_select_lines_by_box(In, &box, GV_POINTS | GV_LINES, List);
  66. G_debug(3, " %d lines selected by box", List->n_values);
  67. current_distance = 2 * buffer;
  68. for (i = 0; i < List->n_values; i++) {
  69. int line, ltype;
  70. double dist;
  71. line = List->value[i];
  72. G_debug(3, " line[%d] = %d", i, line);
  73. ltype = Vect_read_line(In, Points, NULL, line);
  74. Vect_line_distance(Points, x, y, 0., 0, NULL, NULL, NULL, &dist, NULL,
  75. NULL);
  76. G_debug(3, " dist = %f", dist);
  77. if (dist > buffer)
  78. continue;
  79. /* lines */
  80. if (type & ltype) {
  81. if (dist < current_distance)
  82. current_distance = dist;
  83. }
  84. /* Areas */
  85. if ((type & GV_AREA) && ltype == GV_BOUNDARY) {
  86. int j, side[2], centr[2], area_in;
  87. Vect_get_line_areas(In, line, &side[0], &side[1]);
  88. for (j = 0; j < 2; j++) {
  89. centr[j] = 0;
  90. if (side[j] > 0)
  91. area_in = side[j];
  92. else /* island */
  93. area_in = Vect_get_isle_area(In, abs(side[j]));
  94. if (area_in > 0)
  95. centr[j] = Vect_get_area_centroid(In, area_in);
  96. }
  97. if (centr[0] || centr[1]) {
  98. if (dist < current_distance)
  99. current_distance = dist;
  100. }
  101. }
  102. }
  103. return current_distance;
  104. }
  105. /*
  106. * Test if area in Out is in buffer.
  107. * Return: 1 in buffer
  108. * 0 outside buffer
  109. */
  110. int area_in_buffer(struct Map_info *In, struct Map_info *Out,
  111. int area, int type, double buffer, double tolerance)
  112. {
  113. double dist;
  114. int ret, i;
  115. static struct ilist *List = NULL;
  116. static struct line_pnts *Points = NULL;
  117. double x, y;
  118. G_debug(3, " area_in_buffer(): area = %d", area);
  119. if (List == NULL)
  120. List = Vect_new_list();
  121. if (Points == NULL)
  122. Points = Vect_new_line_struct();
  123. /* Warning: because of tolerance, centroid in area calculated by Vect_get_point_in_area()
  124. * may fall into buffer (arc interpolated by polygon) even if area is outside!!! */
  125. /* Because of finite number of decimal places in double representation, RET is used. */
  126. /* Test1: Centroid (the only reliable, I think).
  127. * There are 3 possible cases for the distance of centroid to nearest input feature:
  128. * 1) < (buffer - tolerance) => area inside the buffer
  129. * 2) > buffer => area outside the buffer
  130. * 3) > (buffer - tolerance) and < buffer (that means within the tolerance) => uncertain */
  131. ret = Vect_get_point_in_area(Out, area, &x, &y);
  132. if (ret == 0) { /* centroid OK */
  133. /* test the distance to nearest input feature */
  134. dist = input_distance(In, type, buffer, x, y);
  135. G_debug(3, " centroid %f, %f dist = %f", x, y, dist);
  136. if (dist < (buffer - tolerance - RET)) {
  137. G_debug(3, " centroid in buffer -> area in buffer");
  138. return 1;
  139. }
  140. else if (dist > (buffer + RET)) {
  141. G_debug(3, " centroid outside buffer -> area outside buffer");
  142. return 0;
  143. }
  144. }
  145. /* Test2: counterclockwise (ccw) boundary
  146. * Boundaries around features are written in ccw order, that means area inside buffer is on the
  147. * left side. Area bundaries are listed in cw order (ccw boundaries as negative).
  148. * So if any boundary in area list is negative, i.e. in cww order, i.e. buffer inside area,
  149. * whole area _must_ be in buffer. But, also areas without such boundary may be in buffer,
  150. * see below. */
  151. /* TODO: The problem!!!: unfortunately it is not true. After snap, break and remove duplicate
  152. * it may happen that ccw line appeareas in the area outside the buffer!!! */
  153. Vect_get_area_boundaries(Out, area, List);
  154. for (i = 0; i < List->n_values; i++) {
  155. if (List->value[i] < 0) {
  156. G_debug(3, " negative boundary -> area in buffer");
  157. return 1;
  158. }
  159. }
  160. /* Test3: Input feature within area.
  161. * I believe, that if no negative boundary was found and area is in buffer,
  162. * the distance of the nearest input feature for at least one area vertex must be < (buffer-tolerance)
  163. * This test is left as last because it is slow (check each vertex). */
  164. Vect_get_area_points(Out, area, Points);
  165. for (i = 0; i < Points->n_points - 1; i++) {
  166. dist = input_distance(In, type, buffer, Points->x[i], Points->y[i]);
  167. G_debug(3, " vertex dist = %f", dist);
  168. if (dist < (buffer - tolerance - RET)) {
  169. G_debug(3, " vertex in buffer -> area in buffer");
  170. return 1;
  171. }
  172. }
  173. /* Test4?: It may be that that Test3 does not cover all possible cases. If so, somebody must
  174. * find such example and send it to me */
  175. G_debug(3, " -> area outside buffer");
  176. return 0;
  177. }
  178. void stop(struct Map_info *In, struct Map_info *Out)
  179. {
  180. Vect_close(In);
  181. G_message(_("Rebuilding topology..."));
  182. Vect_build_partial(Out, GV_BUILD_NONE, NULL);
  183. Vect_build(Out, stderr);
  184. Vect_close(Out);
  185. }
  186. int main(int argc, char *argv[])
  187. {
  188. struct Map_info In, Out;
  189. struct line_pnts *Points, *BPoints;
  190. struct line_cats *Cats, *BCats;
  191. char *mapset;
  192. struct GModule *module;
  193. struct Option *in_opt, *out_opt, *type_opt, *buffer_opt, *tolerance_opt,
  194. *bufcol_opt, *scale_opt, *debug_opt, *field_opt;
  195. double buffer, tolerance, dtmp;
  196. int type, debug;
  197. int ret, nareas, area, nlines, line;
  198. char *Areas, *Lines;
  199. int field;
  200. /* Attributes if sizecol is used */
  201. int i, nrec, ctype;
  202. struct field_info *Fi;
  203. dbDriver *Driver;
  204. dbCatValArray cvarr;
  205. int size_val_int;
  206. double size_val, scale, orig_tolerance;
  207. module = G_define_module();
  208. module->keywords = _("vector");
  209. module->description =
  210. _
  211. ("Creates a buffer around features of given type (areas must contain centroid).");
  212. in_opt = G_define_standard_option(G_OPT_V_INPUT);
  213. out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
  214. type_opt = G_define_standard_option(G_OPT_V_TYPE);
  215. type_opt->options = "point,line,boundary,centroid,area";
  216. type_opt->answer = "point,line,area";
  217. field_opt = G_define_standard_option(G_OPT_V_FIELD);
  218. buffer_opt = G_define_option();
  219. buffer_opt->key = "buffer";
  220. buffer_opt->type = TYPE_DOUBLE;
  221. buffer_opt->required = NO;
  222. buffer_opt->description = _("Buffer distance in map units");
  223. bufcol_opt = G_define_option();
  224. bufcol_opt->key = "bufcol";
  225. bufcol_opt->type = TYPE_STRING;
  226. bufcol_opt->required = NO;
  227. bufcol_opt->description =
  228. _("Attribute column to use for buffer distances");
  229. bufcol_opt->guisection = _("Advanced");
  230. scale_opt = G_define_option();
  231. scale_opt->key = "scale";
  232. scale_opt->type = TYPE_DOUBLE;
  233. scale_opt->required = NO;
  234. scale_opt->answer = "1.0";
  235. scale_opt->description = _("Scaling factor for attribute column values");
  236. scale_opt->guisection = _("Advanced");
  237. tolerance_opt = G_define_option();
  238. tolerance_opt->key = "tolerance";
  239. tolerance_opt->type = TYPE_DOUBLE;
  240. tolerance_opt->required = NO;
  241. tolerance_opt->answer = "0.01";
  242. tolerance_opt->guisection = _("Advanced");
  243. tolerance_opt->description =
  244. _("Maximum distance between theoretical arc and polygon segments "
  245. "as multiple of buffer");
  246. debug_opt = G_define_option();
  247. debug_opt->key = "debug";
  248. debug_opt->type = TYPE_STRING;
  249. debug_opt->required = NO;
  250. debug_opt->options = "buffer,clean";
  251. debug_opt->guisection = _("Advanced");
  252. debug_opt->description = _("Stop the process at a certain stage");
  253. G_gisinit(argv[0]);
  254. if (G_parser(argc, argv))
  255. exit(EXIT_FAILURE);
  256. type = Vect_option_to_types(type_opt);
  257. field = atoi(field_opt->answer);
  258. if ((buffer_opt->answer && bufcol_opt->answer) ||
  259. (!(buffer_opt->answer || bufcol_opt->answer)))
  260. G_fatal_error("Select a buffer distance or column, but not both.");
  261. if (bufcol_opt->answer)
  262. G_warning(_("The bufcol option may contain bugs during the cleaning "
  263. "step. If you encounter problems, use the debug "
  264. "option or clean manually with v.clean tool=break; "
  265. "v.category step=0; v.extract -d type=area"));
  266. orig_tolerance = atof(tolerance_opt->answer);
  267. tolerance = orig_tolerance;
  268. scale = atof(scale_opt->answer);
  269. if (scale <= 0.0)
  270. G_fatal_error("Illegal scale value");
  271. if (buffer_opt->answer) {
  272. buffer = fabs(atof(buffer_opt->answer));
  273. tolerance *= buffer;
  274. G_message(_("The tolerance in map units: %g"), tolerance);
  275. /* At least 8 points for circle. */
  276. dtmp = 0.999 * buffer * (1 - cos(2 * PI / 8 / 2));
  277. G_debug(3, "Minimum tolerance = %f", dtmp);
  278. if (tolerance > dtmp) {
  279. tolerance = dtmp;
  280. G_warning(_("The tolerance was reset to %g (map units)"),
  281. tolerance);
  282. }
  283. }
  284. debug = DEBUG_NONE;
  285. if (debug_opt->answer) {
  286. if (debug_opt->answer[0] == 'b')
  287. debug = DEBUG_BUFFER;
  288. else if (debug_opt->answer[0] == 'c')
  289. debug = DEBUG_CLEAN;
  290. }
  291. Vect_check_input_output_name(in_opt->answer, out_opt->answer,
  292. GV_FATAL_EXIT);
  293. Points = Vect_new_line_struct();
  294. BPoints = Vect_new_line_struct();
  295. Cats = Vect_new_cats_struct();
  296. BCats = Vect_new_cats_struct();
  297. /* open input vector */
  298. if ((mapset = G_find_vector2(in_opt->answer, "")) == NULL) {
  299. G_fatal_error(_("Vector map <%s> not found"), in_opt->answer);
  300. }
  301. Vect_set_open_level(2);
  302. Vect_open_old(&In, in_opt->answer, mapset);
  303. Vect_set_fatal_error(GV_FATAL_PRINT);
  304. if (0 > Vect_open_new(&Out, out_opt->answer, 0)) {
  305. Vect_close(&In);
  306. exit(EXIT_FAILURE);
  307. }
  308. /* check and load attribute column data */
  309. if (bufcol_opt->answer) {
  310. db_CatValArray_init(&cvarr);
  311. Fi = Vect_get_field(&In, field);
  312. if (Fi == NULL)
  313. G_fatal_error(_("Unable to get layer info for vector map"));
  314. Driver = db_start_driver_open_database(Fi->driver, Fi->database);
  315. if (Driver == NULL)
  316. G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
  317. Fi->database, Fi->driver);
  318. /* Note do not check if the column exists in the table because it may be expression */
  319. /* TODO: only select values we need instead of all in column */
  320. nrec = db_select_CatValArray(Driver, Fi->table, Fi->key,
  321. bufcol_opt->answer, NULL, &cvarr);
  322. if (nrec < 0)
  323. G_fatal_error(_("Unable to select data from table"));
  324. G_debug(2, "%d records selected from table", nrec);
  325. ctype = cvarr.ctype;
  326. if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE)
  327. G_fatal_error(_("Column type not supported"));
  328. db_close_database_shutdown_driver(Driver);
  329. for (i = 0; i < cvarr.n_values; i++) {
  330. if (ctype == DB_C_TYPE_INT) {
  331. G_debug(4, "cat = %d val = %d", cvarr.value[i].cat,
  332. cvarr.value[i].val.i);
  333. }
  334. else if (ctype == DB_C_TYPE_DOUBLE) {
  335. G_debug(4, "cat = %d val = %f", cvarr.value[i].cat,
  336. cvarr.value[i].val.d);
  337. }
  338. }
  339. }
  340. Vect_copy_head_data(&In, &Out);
  341. Vect_hist_copy(&In, &Out);
  342. Vect_hist_command(&Out);
  343. /* Create buffers' boundaries */
  344. /* Lines (and Points) */
  345. if ((type & GV_POINTS) || (type & GV_LINES)) {
  346. int nlines, line, ltype;
  347. nlines = Vect_get_num_lines(&In);
  348. G_message(_("Lines buffers... "));
  349. for (line = 1; line <= nlines; line++) {
  350. int cat;
  351. G_debug(3, "line = %d", line);
  352. G_percent(line, nlines, 2);
  353. ltype = Vect_read_line(&In, Points, Cats, line);
  354. if (!(ltype & type))
  355. continue;
  356. if (!Vect_cat_get(Cats, field, &cat))
  357. continue;
  358. if (bufcol_opt->answer) {
  359. /* get value from sizecol column */
  360. /* should probably be put in a function */
  361. if (ctype == DB_C_TYPE_INT) {
  362. ret =
  363. db_CatValArray_get_value_int(&cvarr, cat,
  364. &size_val_int);
  365. if (ret != DB_OK) {
  366. G_warning(_("No record for category %d in table <%s>"),
  367. cat, Fi->table);
  368. continue;
  369. }
  370. size_val = (double)size_val_int;
  371. }
  372. if (ctype == DB_C_TYPE_DOUBLE) {
  373. ret =
  374. db_CatValArray_get_value_double(&cvarr, cat,
  375. &size_val);
  376. if (ret != DB_OK) {
  377. G_warning(_("No record for category %d in table <%s>"),
  378. cat, Fi->table);
  379. continue;
  380. }
  381. }
  382. if (size_val < 0.0) {
  383. G_warning(_("Attribute is of invalid size (%.3f) for category %d"),
  384. size_val, cat);
  385. continue;
  386. }
  387. if (size_val == 0.0)
  388. continue;
  389. buffer = size_val * scale;
  390. G_debug(2, " dynamic buffer size = %.2f", buffer);
  391. tolerance = orig_tolerance * buffer;
  392. G_debug(2, _("The tolerance in map units: %g"), tolerance);
  393. /* At least 8 points for circle. */
  394. dtmp = 0.999 * buffer * (1 - cos(2 * PI / 8 / 2));
  395. G_debug(2, "Minimum tolerance = %f", dtmp);
  396. if (tolerance > dtmp) {
  397. tolerance = dtmp;
  398. G_warning(_("The tolerance was reset to %g (map units). [category %d]"),
  399. tolerance, cat);
  400. }
  401. }
  402. Vect_line_buffer(Points, buffer, tolerance, BPoints);
  403. Vect_write_line(&Out, GV_BOUNDARY, BPoints, BCats);
  404. }
  405. }
  406. /* Areas */
  407. if (type & GV_AREA) {
  408. int i, nareas, area, centroid, nisles, isle;
  409. nareas = Vect_get_num_areas(&In);
  410. G_message(_("Areas buffers... "));
  411. for (area = 1; area <= nareas; area++) {
  412. int cat;
  413. G_percent(area, nareas, 2);
  414. centroid = Vect_get_area_centroid(&In, area);
  415. if (centroid == 0)
  416. continue;
  417. Vect_read_line(&In, NULL, Cats, centroid);
  418. if (!Vect_cat_get(Cats, field, &cat))
  419. continue;
  420. if (bufcol_opt->answer) {
  421. /* get value from sizecol column */
  422. if (ctype == DB_C_TYPE_INT) {
  423. ret =
  424. db_CatValArray_get_value_int(&cvarr, cat,
  425. &size_val_int);
  426. if (ret != DB_OK) {
  427. G_warning(_("No record for category %d in table <%s>"),
  428. cat, Fi->table);
  429. continue;
  430. }
  431. size_val = (double)size_val_int;
  432. }
  433. if (ctype == DB_C_TYPE_DOUBLE) {
  434. ret =
  435. db_CatValArray_get_value_double(&cvarr, cat,
  436. &size_val);
  437. if (ret != DB_OK) {
  438. G_warning(_("No record for category %d in table <%s>"),
  439. cat, Fi->table);
  440. continue;
  441. }
  442. }
  443. if (size_val < 0.0) {
  444. G_warning(_("Attribute is of invalid size (%.3f) for category %d"),
  445. size_val, cat);
  446. continue;
  447. }
  448. if (size_val == 0.0)
  449. continue;
  450. buffer = size_val * scale;
  451. G_debug(2, " dynamic buffer size = %.2f", buffer);
  452. tolerance = orig_tolerance * buffer;
  453. G_debug(2, _("The tolerance in map units: %g"), tolerance);
  454. /* At least 8 points for circle. */
  455. dtmp = 0.999 * buffer * (1 - cos(2 * PI / 8 / 2));
  456. G_debug(2, "Minimum tolerance = %f", dtmp);
  457. if (tolerance > dtmp) {
  458. tolerance = dtmp;
  459. G_warning(_("The tolerance was reset to %g (map units). [category %d]"),
  460. tolerance, cat);
  461. }
  462. }
  463. /* outer ring */
  464. Vect_get_area_points(&In, area, Points);
  465. Vect_line_buffer(Points, buffer, tolerance, BPoints);
  466. Vect_write_line(&Out, GV_BOUNDARY, BPoints, BCats);
  467. /* islands */
  468. nisles = Vect_get_area_num_isles(&In, area);
  469. for (i = 0; i < nisles; i++) {
  470. double l;
  471. isle = Vect_get_area_isle(&In, area, i);
  472. Vect_get_isle_points(&In, isle, Points);
  473. /* Check if the isle is big enough */
  474. l = Vect_line_length(Points);
  475. if (l / 2 < 2 * buffer)
  476. continue;
  477. Vect_line_buffer(Points, buffer, tolerance, BPoints);
  478. Vect_write_line(&Out, GV_BOUNDARY, BPoints, BCats);
  479. }
  480. }
  481. }
  482. if (debug == DEBUG_BUFFER) {
  483. stop(&In, &Out);
  484. exit(EXIT_SUCCESS);
  485. }
  486. /* Create areas */
  487. /* Break lines */
  488. G_message(_("Building parts of topology..."));
  489. Vect_build_partial(&Out, GV_BUILD_BASE, stderr);
  490. /* Warning: snapping must be done, otherwise colinear boundaries are not broken and
  491. * topology cannot be built (the same angle). But snapping distance must be very, very
  492. * small, otherwise counterclockwise boundaries can appear in areas outside the buffer.
  493. * I have done some tests on real data (projected) and threshold 1e-8 was not enough,
  494. * Snapping threshold 1e-7 seems to work. Don't increase until we find example
  495. * where it is not sufficient. */
  496. /* TODO: look at snapping threshold better, calculate some theoretical value to avoid
  497. * the same angles of lines at nodes, don't forget about LongLat data, probably
  498. * calculate different threshold for each map, depending on map's bounding box */
  499. G_message(_("Snapping boundaries..."));
  500. Vect_snap_lines(&Out, GV_BOUNDARY, 1e-7, NULL, stderr);
  501. G_message(_("Breaking boundaries..."));
  502. Vect_break_lines(&Out, GV_BOUNDARY, NULL, stderr);
  503. G_message(_("Removing duplicates..."));
  504. Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL, stderr);
  505. /* Dangles and bridges don't seem to be necessary if snapping is small enough. */
  506. /*
  507. G_message ( "Removing dangles..." );
  508. Vect_remove_dangles ( &Out, GV_BOUNDARY, -1, NULL, stderr );
  509. G_message ( "Removing bridges..." );
  510. Vect_remove_bridges ( &Out, NULL, stderr );
  511. */
  512. G_message(_("Attaching islands..."));
  513. Vect_build_partial(&Out, GV_BUILD_ATTACH_ISLES, stderr);
  514. /* Calculate new centroids for all areas */
  515. nareas = Vect_get_num_areas(&Out);
  516. Areas = (char *)G_calloc(nareas + 1, sizeof(char));
  517. for (area = 1; area <= nareas; area++) {
  518. G_debug(3, "area = %d", area);
  519. /*** BUG *** if dynamic bufcol was used, "buffer" will only hold last value ***/
  520. ret = area_in_buffer(&In, &Out, area, type, buffer, tolerance);
  521. if (ret) {
  522. G_debug(3, " -> in buffer");
  523. Areas[area] = 1;
  524. }
  525. /* Write out centroid (before check if correct, so that it isd visible for debug) */
  526. if (debug == DEBUG_CLEAN) {
  527. double x, y;
  528. ret = Vect_get_point_in_area(&Out, area, &x, &y);
  529. if (ret < 0) {
  530. G_warning(_("Cannot calculate area centroid"));
  531. continue;
  532. }
  533. Vect_reset_cats(Cats);
  534. if (Areas[area])
  535. Vect_cat_set(Cats, 1, 1);
  536. Vect_reset_line(Points);
  537. Vect_append_point(Points, x, y, 0.);
  538. Vect_write_line(&Out, GV_CENTROID, Points, Cats);
  539. }
  540. }
  541. if (debug == DEBUG_CLEAN) {
  542. stop(&In, &Out);
  543. exit(EXIT_SUCCESS);
  544. }
  545. /* Make a list of boundaries to be deleted (both sides inside) */
  546. nlines = Vect_get_num_lines(&Out);
  547. G_debug(3, "nlines = %d", nlines);
  548. Lines = (char *)G_calloc(nlines + 1, sizeof(char));
  549. for (line = 1; line <= nlines; line++) {
  550. int j, side[2], areas[2];
  551. G_debug(3, "line = %d", line);
  552. if (!Vect_line_alive(&Out, line))
  553. continue;
  554. Vect_get_line_areas(&Out, line, &side[0], &side[1]);
  555. for (j = 0; j < 2; j++) {
  556. if (side[j] == 0) { /* area/isle not build */
  557. areas[j] = 0;
  558. }
  559. else if (side[j] > 0) { /* area */
  560. areas[j] = side[j];
  561. }
  562. else { /* < 0 -> island */
  563. areas[j] = Vect_get_isle_area(&Out, abs(side[j]));
  564. }
  565. }
  566. G_debug(3, " areas = %d , %d -> Areas = %d, %d", areas[0], areas[1],
  567. Areas[areas[0]], Areas[areas[1]]);
  568. if (Areas[areas[0]] && Areas[areas[1]])
  569. Lines[line] = 1;
  570. }
  571. G_free(Areas);
  572. /* Delete boundaries */
  573. for (line = 1; line <= nlines; line++) {
  574. if (Lines[line]) {
  575. G_debug(3, " delete line %d", line);
  576. Vect_delete_line(&Out, line);
  577. }
  578. }
  579. G_free(Lines);
  580. /* Create new centroids */
  581. Vect_reset_cats(Cats);
  582. Vect_cat_set(Cats, 1, 1);
  583. nareas = Vect_get_num_areas(&Out);
  584. for (area = 1; area <= nareas; area++) {
  585. double x, y;
  586. G_debug(3, "area = %d", area);
  587. if (!Vect_area_alive(&Out, area))
  588. continue;
  589. /*** BUG *** if dynamic bufcol was used, "buffer" will only hold last value ***/
  590. ret = area_in_buffer(&In, &Out, area, type, buffer, tolerance);
  591. if (ret) {
  592. ret = Vect_get_point_in_area(&Out, area, &x, &y);
  593. if (ret < 0) {
  594. G_warning(_("Cannot calculate area centroid"));
  595. continue;
  596. }
  597. Vect_reset_line(Points);
  598. Vect_append_point(Points, x, y, 0.);
  599. Vect_write_line(&Out, GV_CENTROID, Points, Cats);
  600. }
  601. }
  602. G_message(_("Attaching centroids..."));
  603. Vect_build_partial(&Out, GV_BUILD_CENTROIDS, stderr);
  604. stop(&In, &Out);
  605. exit(EXIT_SUCCESS);
  606. }