misc.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  1. /****************************************************************
  2. *
  3. * MODULE: v.generalize
  4. *
  5. * AUTHOR(S): Daniel Bundala, Markus Metz
  6. *
  7. * PURPOSE: miscellaneous functions of v.generalize
  8. *
  9. *
  10. * COPYRIGHT: (C) 2002-2005 by the GRASS Development Team
  11. *
  12. * This program is free software under the
  13. * GNU General Public License (>=v2).
  14. * Read the file COPYING that comes with GRASS
  15. * for details.
  16. *
  17. ****************************************************************/
  18. #include <stdlib.h>
  19. #include <grass/gis.h>
  20. #include <grass/vector.h>
  21. #include <grass/dbmi.h>
  22. #include <grass/glocale.h>
  23. #include "misc.h"
  24. static int topo_debug = 0;
  25. int set_topo_debug(void)
  26. {
  27. if (getenv("GRASS_VECTOR_TOPO_DEBUG"))
  28. topo_debug = 1;
  29. return topo_debug;
  30. }
  31. int type_mask(struct Option *type_opt)
  32. {
  33. int res = 0;
  34. int i;
  35. for (i = 0; type_opt->answers[i]; i++)
  36. switch (type_opt->answers[i][0]) {
  37. case 'l':
  38. res |= GV_LINE;
  39. break;
  40. case 'b':
  41. res |= GV_BOUNDARY;
  42. break;
  43. case 'a':
  44. res |= GV_BOUNDARY;
  45. }
  46. return res;
  47. }
  48. int get_furthest(struct line_pnts *Points, int a, int b, int with_z,
  49. double *dist)
  50. {
  51. int index = a;
  52. double d = 0;
  53. int i;
  54. double x0 = Points->x[a];
  55. double x1 = Points->x[b];
  56. double y0 = Points->y[a];
  57. double y1 = Points->y[b];
  58. double z0 = Points->z[a];
  59. double z1 = Points->z[b];
  60. double px, py, pz, pdist, di;
  61. int status;
  62. for (i = a + 1; i < b; i++) {
  63. di = dig_distance2_point_to_line(Points->x[i], Points->y[i],
  64. Points->z[i], x0, y0, z0, x1, y1, z1,
  65. with_z, &px, &py, &pz, &pdist,
  66. &status);
  67. if (di > d) {
  68. d = di;
  69. index = i;
  70. }
  71. }
  72. *dist = d;
  73. return index;
  74. }
  75. /* TODO: The collection of categories is horrible in current version!
  76. * Everything repeats many times. We need some data structure
  77. * implementing set! */
  78. int copy_tables_by_cats(struct Map_info *In, struct Map_info *Out)
  79. {
  80. /* this is the (mostly) code from v.extract, it should be moved to
  81. * some vector library (probably) */
  82. int nlines, line, nfields;
  83. int ttype, ntabs = 0;
  84. struct field_info *IFi, *OFi;
  85. struct line_cats *Cats;
  86. int **ocats, *nocats, *fields;
  87. int i;
  88. /* Collect list of output cats */
  89. Cats = Vect_new_cats_struct();
  90. nfields = Vect_cidx_get_num_fields(In);
  91. ocats = (int **)G_malloc(nfields * sizeof(int *));
  92. nocats = (int *)G_malloc(nfields * sizeof(int));
  93. fields = (int *)G_malloc(nfields * sizeof(int));
  94. for (i = 0; i < nfields; i++) {
  95. nocats[i] = 0;
  96. ocats[i] =
  97. (int *)G_malloc(Vect_cidx_get_num_cats_by_index(In, i) *
  98. sizeof(int));
  99. fields[i] = Vect_cidx_get_field_number(In, i);
  100. }
  101. nlines = Vect_get_num_lines(Out);
  102. for (line = 1; line <= nlines; line++) {
  103. Vect_read_line(Out, NULL, Cats, line);
  104. for (i = 0; i < Cats->n_cats; i++) {
  105. int f = 0, j;
  106. for (j = 0; j < nfields; j++) { /* find field */
  107. if (fields[j] == Cats->field[i]) {
  108. f = j;
  109. break;
  110. }
  111. }
  112. ocats[f][nocats[f]] = Cats->cat[i];
  113. nocats[f]++;
  114. }
  115. }
  116. /* Copy tables */
  117. G_message(_("Writing attributes..."));
  118. /* Number of output tabs */
  119. for (i = 0; i < Vect_get_num_dblinks(In); i++) {
  120. int j, f = -1;
  121. IFi = Vect_get_dblink(In, i);
  122. for (j = 0; j < nfields; j++) { /* find field */
  123. if (fields[j] == IFi->number) {
  124. f = j;
  125. break;
  126. }
  127. }
  128. if (f >= 0 && nocats[f] > 0)
  129. ntabs++;
  130. }
  131. if (ntabs > 1)
  132. ttype = GV_MTABLE;
  133. else
  134. ttype = GV_1TABLE;
  135. for (i = 0; i < nfields; i++) {
  136. int ret;
  137. if (fields[i] == 0)
  138. continue;
  139. if (nocats[i] == 0)
  140. continue;
  141. /* if ( fields[i] == field && new_cat != -1 ) continue; */
  142. G_message(_("Layer %d"), fields[i]);
  143. /* Make a list of categories */
  144. IFi = Vect_get_field(In, fields[i]);
  145. if (!IFi) { /* no table */
  146. G_warning(_("Database connection not defined for layer %d"),
  147. fields[i]);
  148. continue;
  149. }
  150. OFi = Vect_default_field_info(Out, IFi->number, IFi->name, ttype);
  151. ret = db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table,
  152. OFi->driver, Vect_subst_var(OFi->database,
  153. Out),
  154. OFi->table, IFi->key, ocats[i],
  155. nocats[i]);
  156. if (ret == DB_FAILED) {
  157. G_warning(_("Unable to copy table <%s>"), IFi->table);
  158. }
  159. else {
  160. Vect_map_add_dblink(Out, OFi->number, OFi->name, OFi->table,
  161. IFi->key, OFi->database, OFi->driver);
  162. }
  163. }
  164. for (i = 0; i < nfields; i++)
  165. G_free(ocats[i]);
  166. G_free(ocats);
  167. G_free(nocats);
  168. G_free(fields);
  169. return 1;
  170. }
  171. static int cmp(const void *a, const void *b)
  172. {
  173. int ai = *(int *)a;
  174. int bi = *(int *)b;
  175. return (ai < bi ? -1 : (ai > bi));
  176. }
  177. /* check topology corruption by boundary modification
  178. * return 0 on corruption, 1 if modification is ok */
  179. int check_topo(struct Map_info *Out, int line, struct line_pnts *APoints,
  180. struct line_pnts *Points, struct line_cats *Cats)
  181. {
  182. int i, j, k, intersect, newline;
  183. struct bound_box box, abox, tbox;
  184. struct bound_box lbox, rbox, areabox;
  185. struct line_pnts **AXLines, **BXLines;
  186. int naxlines, nbxlines;
  187. static struct line_pnts *BPoints = NULL;
  188. static struct boxlist *List = NULL;
  189. static struct line_pnts *BPoints2 = NULL;
  190. static struct ilist *BList = NULL;
  191. int area, isle, centr;
  192. int left_o, left_n, right_o, right_n;
  193. int node, node_n_lines;
  194. float angle1, angle2;
  195. off_t offset;
  196. /* topology debugging */
  197. int area_l_o, area_r_o, area_l_n, area_r_n;
  198. int centr_l_o, centr_r_o, centr_l_n, centr_r_n;
  199. int *isles_l_o, nisles_l_o, *isles_l_n, nisles_l_n;
  200. int *isles_r_o, nisles_r_o, *isles_r_n, nisles_r_n;
  201. int found;
  202. if (!BPoints) {
  203. BPoints = Vect_new_line_struct();
  204. BPoints2 = Vect_new_line_struct();
  205. List = Vect_new_boxlist(1);
  206. BList = Vect_new_list();
  207. }
  208. if (APoints->n_points == Points->n_points) {
  209. int same = 1;
  210. for (i = 0; i < APoints->n_points; i++) {
  211. if (APoints->x[i] != Points->x[i] || APoints->y[i] != Points->y[i]) {
  212. same = 0;
  213. break;
  214. }
  215. }
  216. if (same)
  217. return 1;
  218. }
  219. i = APoints->n_points - 1;
  220. if (APoints->x[0] == APoints->x[i] && APoints->y[0] == APoints->y[i]) {
  221. i = Points->n_points - 1;
  222. if (Points->x[0] != Points->x[i] || Points->y[0] != Points->y[i]) {
  223. /* input line forms a loop, output not */
  224. return 0;
  225. }
  226. }
  227. /* test node angles
  228. * an area can be built only if there are no two lines with the same
  229. * angle at the same node */
  230. /* line start */
  231. angle1 = dig_calc_begin_angle(Points, 0);
  232. if (angle1 == -9)
  233. return 0;
  234. node = dig_find_node(&(Out->plus), Points->x[0], Points->y[0], Points->z[0]);
  235. if (node) {
  236. /* if another line exists with the same angle at this node,
  237. * an area can not be constructed -> error */
  238. node_n_lines = Vect_get_node_n_lines(Out, node);
  239. for (i = 0; i < node_n_lines; i++) {
  240. if (abs(Vect_get_node_line(Out, node, i)) == line)
  241. continue;
  242. if (angle1 == Vect_get_node_line_angle(Out, node, i))
  243. return 0;
  244. }
  245. }
  246. /* line end */
  247. angle2 = dig_calc_end_angle(Points, 0);
  248. if (angle2 == -9)
  249. return 0;
  250. i = Points->n_points - 1;
  251. if (Points->x[0] == Points->x[i] && Points->y[0] == Points->y[i]) {
  252. if (angle1 == angle2) {
  253. /* same angle, same start and end coordinates,
  254. * an area can not be constructed -> error */
  255. return 0;
  256. }
  257. }
  258. else {
  259. node = dig_find_node(&(Out->plus), Points->x[i], Points->y[i], Points->z[i]);
  260. }
  261. if (node) {
  262. /* if another line exists with the same angle at this node,
  263. * an area can not be constructed -> error */
  264. node_n_lines = Vect_get_node_n_lines(Out, node);
  265. for (i = 0; i < node_n_lines; i++) {
  266. if (abs(Vect_get_node_line(Out, node, i)) == line)
  267. continue;
  268. if (angle2 == Vect_get_node_line_angle(Out, node, i))
  269. return 0;
  270. }
  271. }
  272. Vect_line_box(Points, &box);
  273. /* Check the modified boundary for self-intersection */
  274. AXLines = BXLines = NULL;
  275. Vect_line_intersection2(Points, NULL, &box, &box, &AXLines, &BXLines,
  276. &naxlines, &nbxlines, 0);
  277. /* Free */
  278. if (naxlines > 0) {
  279. for (j = 0; j < naxlines; j++) {
  280. Vect_destroy_line_struct(AXLines[j]);
  281. }
  282. }
  283. if (AXLines)
  284. G_free(AXLines);
  285. if (naxlines > 0)
  286. return 0;
  287. /* Check intersection of the modified boundary with other boundaries */
  288. Vect_select_lines_by_box(Out, &box, GV_BOUNDARY, List);
  289. intersect = 0;
  290. for (i = 0; i < List->n_values; i++) {
  291. int bline;
  292. bline = List->id[i];
  293. if (bline == line)
  294. continue;
  295. Vect_read_line(Out, BPoints, NULL, bline);
  296. /* Vect_line_intersection is quite slow, hopefully not so bad because only few
  297. * intersections should be found if any */
  298. AXLines = BXLines = NULL;
  299. Vect_line_intersection2(Points, BPoints, &box, &List->box[i],
  300. &AXLines, &BXLines,
  301. &naxlines, &nbxlines, 0);
  302. G_debug(4,
  303. "bline = %d intersect = %d naxlines = %d nbxlines = %d",
  304. bline, intersect, naxlines, nbxlines);
  305. /* Free */
  306. if (naxlines > 0) {
  307. for (j = 0; j < naxlines; j++) {
  308. Vect_destroy_line_struct(AXLines[j]);
  309. }
  310. }
  311. if (AXLines)
  312. G_free(AXLines);
  313. if (nbxlines > 0) {
  314. for (j = 0; j < nbxlines; j++) {
  315. Vect_destroy_line_struct(BXLines[j]);
  316. }
  317. }
  318. if (BXLines)
  319. G_free(BXLines);
  320. if (naxlines > 1 || nbxlines > 1) {
  321. intersect = 1;
  322. break;
  323. }
  324. }
  325. /* modified boundary intersects another boundary */
  326. if (intersect)
  327. return 0;
  328. /* test centroid attachment (point-in-poly) */
  329. Vect_get_line_areas(Out, line, &left_o, &right_o);
  330. Vect_line_box(APoints, &abox);
  331. /* centroid on the left side */
  332. isle = centr = 0;
  333. area = left_o;
  334. if (area < 0) {
  335. isle = -area;
  336. area = Vect_get_isle_area(Out, isle);
  337. }
  338. if (area > 0)
  339. centr = Vect_get_area_centroid(Out, area);
  340. centr_l_o = centr;
  341. area_l_o = area;
  342. lbox = box;
  343. if (isle)
  344. Vect_get_isle_boundaries(Out, isle, BList);
  345. else
  346. Vect_get_area_boundaries(Out, area, BList);
  347. Vect_reset_line(BPoints2);
  348. for (i = 0; i < BList->n_values; i++) {
  349. int bline = BList->value[i];
  350. int dir = bline > 0 ? GV_FORWARD : GV_BACKWARD;
  351. if (abs(bline) != line) {
  352. Vect_read_line(Out, BPoints, NULL, abs(bline));
  353. Vect_line_box(BPoints, &tbox);
  354. Vect_box_extend(&lbox, &tbox);
  355. Vect_append_points(BPoints2, BPoints, dir);
  356. }
  357. else
  358. Vect_append_points(BPoints2, Points, dir);
  359. BPoints2->n_points--; /* skip last point, avoids duplicates */
  360. }
  361. BPoints2->n_points++; /* close polygon */
  362. if (centr > 0) {
  363. int ret;
  364. double cx, cy, cz;
  365. Vect_read_line(Out, BPoints, NULL, centr);
  366. cx = BPoints->x[0];
  367. cy = BPoints->y[0];
  368. cz = BPoints->z[0];
  369. if (Vect_point_in_box(cx, cy, cz, &box) ||
  370. Vect_point_in_box(cx, cy, cz, &abox)) {
  371. ret = Vect_point_in_poly(cx, cy, BPoints2);
  372. if (!isle) {
  373. /* area: centroid must be inside */
  374. if (ret != 1)
  375. return 0;
  376. }
  377. else {
  378. /* isle: centroid must be outside */
  379. if (ret > 0)
  380. return 0;
  381. }
  382. }
  383. }
  384. /* centroid on the right side */
  385. isle = centr = 0;
  386. area = right_o;
  387. if (area < 0) {
  388. isle = -area;
  389. area = Vect_get_isle_area(Out, isle);
  390. }
  391. if (area > 0)
  392. centr = Vect_get_area_centroid(Out, area);
  393. centr_r_o = centr;
  394. area_r_o = area;
  395. rbox = box;
  396. if (isle)
  397. Vect_get_isle_boundaries(Out, isle, BList);
  398. else
  399. Vect_get_area_boundaries(Out, area, BList);
  400. Vect_reset_line(BPoints2);
  401. for (i = 0; i < BList->n_values; i++) {
  402. int bline = BList->value[i];
  403. int dir = bline > 0 ? GV_FORWARD : GV_BACKWARD;
  404. if (abs(bline) != line) {
  405. Vect_read_line(Out, BPoints, NULL, abs(bline));
  406. Vect_line_box(BPoints, &tbox);
  407. Vect_box_extend(&rbox, &tbox);
  408. Vect_append_points(BPoints2, BPoints, dir);
  409. }
  410. else
  411. Vect_append_points(BPoints2, Points, dir);
  412. BPoints2->n_points--; /* skip last point, avoids duplicates */
  413. }
  414. BPoints2->n_points++; /* close polygon */
  415. if (centr > 0) {
  416. int ret;
  417. double cx, cy, cz;
  418. Vect_read_line(Out, BPoints, NULL, centr);
  419. cx = BPoints->x[0];
  420. cy = BPoints->y[0];
  421. cz = BPoints->z[0];
  422. if (Vect_point_in_box(cx, cy, cz, &box) ||
  423. Vect_point_in_box(cx, cy, cz, &abox)) {
  424. ret = Vect_point_in_poly(cx, cy, BPoints2);
  425. if (!isle) {
  426. /* area: centroid must be inside */
  427. if (ret != 1)
  428. return 0;
  429. }
  430. else {
  431. /* isle: centroid must be outside */
  432. if (ret > 0)
  433. return 0;
  434. }
  435. }
  436. }
  437. /* all fine:
  438. * areas/isles can be built
  439. * no intersection with another boundary, e.g. isle attachment will be preserved
  440. * centroids are still on the correct side of the boundary */
  441. if (!topo_debug) {
  442. /* update only those parts of topology that actually get changed */
  443. /* boundary:
  444. * node in case of loop support
  445. * node angles
  446. * bounding box */
  447. /* rewrite boundary on level 1 */
  448. offset = Out->plus.Line[line]->offset;
  449. Out->level = 1;
  450. offset = Vect_rewrite_line(Out, offset, GV_BOUNDARY, Points, Cats);
  451. Out->level = 2;
  452. /* delete line from topo */
  453. dig_del_line(&Out->plus, line, APoints->x[0], APoints->y[0], APoints->z[0]);
  454. /* restore line in topo */
  455. dig_restore_line(&Out->plus, line, GV_BOUNDARY, Points, &box, offset);
  456. /* update area/isle box to the left */
  457. if (left_o < 0) {
  458. dig_spidx_del_isle(&Out->plus, -left_o);
  459. dig_spidx_add_isle(&Out->plus, -left_o, &lbox);
  460. }
  461. else if (left_o > 0) {
  462. dig_spidx_del_area(&Out->plus, left_o);
  463. dig_spidx_add_area(&Out->plus, left_o, &lbox);
  464. }
  465. /* update area/isle box to the right */
  466. if (right_o < 0) {
  467. dig_spidx_del_isle(&Out->plus, -right_o);
  468. dig_spidx_add_isle(&Out->plus, -right_o, &rbox);
  469. }
  470. else if (right_o > 0) {
  471. dig_spidx_del_area(&Out->plus, right_o);
  472. dig_spidx_add_area(&Out->plus, right_o, &rbox);
  473. }
  474. /* done */
  475. return 1;
  476. }
  477. /* debug topology */
  478. /* record isles of the old areas to the left and right */
  479. nisles_l_o = 0;
  480. isles_l_o = NULL;
  481. if (area_l_o) {
  482. nisles_l_o = Out->plus.Area[area_l_o]->n_isles;
  483. if (nisles_l_o) {
  484. isles_l_o = G_malloc(nisles_l_o * sizeof(int));
  485. for (i = 0; i < nisles_l_o; i++) {
  486. isles_l_o[i] = Out->plus.Area[area_l_o]->isles[i];
  487. }
  488. qsort(isles_l_o, nisles_l_o, sizeof(int), cmp);
  489. }
  490. }
  491. nisles_r_o = 0;
  492. isles_r_o = NULL;
  493. if (area_r_o) {
  494. nisles_r_o = Out->plus.Area[area_r_o]->n_isles;
  495. if (nisles_r_o) {
  496. isles_r_o = G_malloc(nisles_r_o * sizeof(int));
  497. for (i = 0; i < nisles_r_o; i++) {
  498. isles_r_o[i] = Out->plus.Area[area_r_o]->isles[i];
  499. }
  500. qsort(isles_r_o, nisles_r_o, sizeof(int), cmp);
  501. }
  502. }
  503. /* OK, rewrite modified boundary */
  504. newline = Vect_rewrite_line(Out, line, GV_BOUNDARY, Points, Cats);
  505. if (newline != line)
  506. G_fatal_error("Vect_rewrite_line(): new line id %d != old line id %d",
  507. newline, line);
  508. /* get new area and centroid ids to the left and right */
  509. centr_l_n = centr_r_n = 0;
  510. Vect_get_line_areas(Out, newline, &left_n, &right_n);
  511. area = left_n;
  512. if (area < 0)
  513. area = Vect_get_isle_area(Out, -area);
  514. if (area > 0)
  515. centr_l_n = Vect_get_area_centroid(Out, area);
  516. area_l_n = area;
  517. area = right_n;
  518. if (area < 0)
  519. area = Vect_get_isle_area(Out, -area);
  520. if (area > 0)
  521. centr_r_n = Vect_get_area_centroid(Out, area);
  522. area_r_n = area;
  523. /* record isles of the new areas to the left and right */
  524. nisles_l_n = 0;
  525. isles_l_n = NULL;
  526. if (area_l_n) {
  527. nisles_l_n = Out->plus.Area[area_l_n]->n_isles;
  528. if (nisles_l_n) {
  529. isles_l_n = G_malloc(nisles_l_n * sizeof(int));
  530. for (i = 0; i < nisles_l_n; i++) {
  531. isles_l_n[i] = Out->plus.Area[area_l_n]->isles[i];
  532. }
  533. qsort(isles_l_n, nisles_l_n, sizeof(int), cmp);
  534. }
  535. }
  536. nisles_r_n = 0;
  537. isles_r_n = NULL;
  538. if (area_r_n) {
  539. nisles_r_n = Out->plus.Area[area_r_n]->n_isles;
  540. if (nisles_r_n) {
  541. isles_r_n = G_malloc(nisles_r_n * sizeof(int));
  542. for (i = 0; i < nisles_r_n; i++) {
  543. isles_r_n[i] = Out->plus.Area[area_r_n]->isles[i];
  544. }
  545. qsort(isles_r_n, nisles_r_n, sizeof(int), cmp);
  546. }
  547. }
  548. /* compare isle numbers and ids on the left and right */
  549. /* left */
  550. if (nisles_l_o != nisles_l_n)
  551. G_fatal_error("Number of isles to the left differ: old %d, new %d",
  552. nisles_l_o, nisles_l_n);
  553. found = 0;
  554. k = 0;
  555. for (i = 0; i < nisles_l_o; i++) {
  556. if (isles_l_o[i] != isles_l_n[k]) {
  557. if (!found) {
  558. found = 1;
  559. k--;
  560. }
  561. else {
  562. for (j = 0; j < nisles_l_o; j++) {
  563. G_message("old %d new %d", isles_l_o[j], isles_l_n[j]);
  564. }
  565. G_fatal_error("New isle to the left %d is wrong",
  566. isles_l_n[i]);
  567. }
  568. }
  569. k++;
  570. }
  571. /* right */
  572. if (nisles_r_o != nisles_r_n)
  573. G_fatal_error("Number of isles to the left differ: old %d, new %d",
  574. nisles_r_o, nisles_r_n);
  575. found = 0;
  576. k = 0;
  577. for (i = 0; i < nisles_r_o; i++) {
  578. if (isles_r_o[i] != isles_r_n[k]) {
  579. if (!found) {
  580. found = 1;
  581. k--;
  582. }
  583. else {
  584. for (j = 0; j < nisles_r_o; j++) {
  585. G_message("old %d new %d", isles_r_o[j], isles_r_n[j]);
  586. }
  587. G_fatal_error("New isle to the right %d is wrong",
  588. isles_l_n[i]);
  589. }
  590. }
  591. k++;
  592. }
  593. /* Check position of centroids */
  594. if (centr_l_n != centr_l_o || centr_r_n != centr_r_o) {
  595. /* should not happen if the above topo checks work as expected */
  596. G_warning("The modified boundary changes attachment of centroid -> topo checks failed");
  597. if (centr_l_n != centr_l_o) {
  598. G_warning("Left area/isle old: %d, new: %d", left_o, left_n);
  599. G_warning("Left centroid old: %d, new: %d", centr_l_o, centr_l_n);
  600. if (centr_l_o) {
  601. int ret1, ret2, ret3;
  602. Vect_read_line(Out, BPoints, NULL, centr_l_o);
  603. Vect_get_area_box(Out, area_l_n, &abox);
  604. ret1 = (BPoints->x[0] >= abox.W && BPoints->x[0] <= abox.E &&
  605. BPoints->y[0] >= abox.S && BPoints->y[0] <= abox.N);
  606. ret2 = Vect_point_in_area_outer_ring(BPoints->x[0], BPoints->y[0], Out,
  607. area_l_n, &abox);
  608. Vect_get_area_points(Out, area_l_n, BPoints2);
  609. ret3 = Vect_point_in_poly(BPoints->x[0], BPoints->y[0], BPoints2);
  610. if (ret2 != ret3) {
  611. G_warning("Left old centroid in new area box: %d", ret1);
  612. G_warning("Left old centroid in new area outer ring: %d", ret2);
  613. G_warning("Left old centroid in new area as poly: %d", ret3);
  614. }
  615. }
  616. }
  617. if (centr_r_n != centr_r_o) {
  618. G_warning("Right area/isle old: %d, new: %d", right_o, right_n);
  619. G_warning("Right centroid old: %d, new: %d", centr_r_o, centr_r_n);
  620. if (centr_r_o) {
  621. int ret1, ret2, ret3;
  622. Vect_read_line(Out, BPoints, NULL, centr_r_o);
  623. Vect_get_area_box(Out, area_r_n, &abox);
  624. ret1 = (BPoints->x[0] >= abox.W && BPoints->x[0] <= abox.E &&
  625. BPoints->y[0] >= abox.S && BPoints->y[0] <= abox.N);
  626. ret2 = Vect_point_in_area_outer_ring(BPoints->x[0], BPoints->y[0], Out,
  627. area_r_n, &abox);
  628. Vect_get_area_points(Out, area_r_n, BPoints2);
  629. ret3 = Vect_point_in_poly(BPoints->x[0], BPoints->y[0], BPoints2);
  630. if (ret2 != ret3) {
  631. G_warning("Right old centroid in new area box: %d", ret1);
  632. G_warning("Right old centroid in new area outer ring: %d", ret2);
  633. G_warning("Right old centroid in new area as poly: %d", ret3);
  634. }
  635. }
  636. }
  637. /* rewrite old line */
  638. newline = Vect_rewrite_line(Out, newline, GV_BOUNDARY, APoints, Cats);
  639. centr_l_n = centr_r_n = 0;
  640. Vect_get_line_areas(Out, newline, &area_l_n, &area_r_n);
  641. area = area_l_n;
  642. if (area < 0)
  643. area = Vect_get_isle_area(Out, -area);
  644. if (area > 0)
  645. centr_l_n = Vect_get_area_centroid(Out, area);
  646. area_l_n = area;
  647. area = area_r_n;
  648. if (area < 0)
  649. area = Vect_get_isle_area(Out, -area);
  650. if (area > 0)
  651. centr_r_n = Vect_get_area_centroid(Out, area);
  652. area_r_n = area;
  653. if (centr_l_n != centr_l_o) {
  654. Vect_get_area_box(Out, area_l_n, &areabox);
  655. if (centr_l_n > 0) {
  656. Vect_read_line(Out, BPoints, NULL, centr_l_n);
  657. if (Vect_point_in_area(BPoints->x[0], BPoints->y[0], Out,
  658. area_l_n, &areabox)) {
  659. G_warning("New left centroid is in new left area %d", area_l_n);
  660. G_warning("New left centroid on outer ring: %d",
  661. Vect_point_in_area_outer_ring(BPoints->x[0], BPoints->y[0], Out,
  662. area_l_n, &areabox));
  663. G_warning("Best area for new left centroid: %d",
  664. Vect_find_area(Out, BPoints->x[0], BPoints->y[0]));
  665. }
  666. else
  667. G_warning("New left centroid is not in new left area");
  668. }
  669. if (centr_l_o > 0) {
  670. Vect_read_line(Out, BPoints, NULL, centr_l_o);
  671. if (Vect_point_in_area(BPoints->x[0], BPoints->y[0], Out,
  672. area_l_n, &areabox)) {
  673. G_warning("Old left centroid is in new left area %d", area_l_n);
  674. G_warning("Old left centroid on outer ring: %d",
  675. Vect_point_in_area_outer_ring(BPoints->x[0], BPoints->y[0], Out,
  676. area_l_n, &areabox));
  677. G_warning("Best area for old left centroid: %d",
  678. Vect_find_area(Out, BPoints->x[0], BPoints->y[0]));
  679. }
  680. else
  681. G_warning("Old left centroid is not in new left area");
  682. }
  683. G_fatal_error("Left centroid old %d, restored %d", centr_l_o, centr_l_n);
  684. return 0;
  685. }
  686. if (centr_r_n != centr_r_o) {
  687. Vect_get_area_box(Out, area_r_n, &areabox);
  688. if (centr_r_n > 0) {
  689. Vect_read_line(Out, BPoints, NULL, centr_r_n);
  690. if (Vect_point_in_area(BPoints->x[0], BPoints->y[0], Out,
  691. area_r_n, &areabox)) {
  692. G_warning("New right centroid is in new right area %d", area_r_n);
  693. G_warning("New right centroid on outer ring: %d",
  694. Vect_point_in_area_outer_ring(BPoints->x[0], BPoints->y[0], Out,
  695. area_r_n, &areabox));
  696. G_warning("Best area for new right centroid: %d",
  697. Vect_find_area(Out, BPoints->x[0], BPoints->y[0]));
  698. }
  699. else
  700. G_warning("New right centroid is not in new right area");
  701. }
  702. if (centr_r_o > 0) {
  703. Vect_read_line(Out, BPoints, NULL, centr_r_o);
  704. if (Vect_point_in_area(BPoints->x[0], BPoints->y[0], Out,
  705. area_r_n, &areabox)) {
  706. G_warning("Old right centroid is in new right area %d", area_r_n);
  707. G_warning("Old right centroid on outer ring: %d",
  708. Vect_point_in_area_outer_ring(BPoints->x[0], BPoints->y[0], Out,
  709. area_r_n, &areabox));
  710. G_warning("Best area for old right centroid: %d",
  711. Vect_find_area(Out, BPoints->x[0], BPoints->y[0]));
  712. }
  713. else
  714. G_warning("Old right centroid is not in new right area");
  715. }
  716. G_fatal_error("Right centroid old %d, restored %d", centr_r_o, centr_r_n);
  717. return 0;
  718. }
  719. G_fatal_error("Topology check failure");
  720. return 0;
  721. }
  722. if (isles_l_o)
  723. G_free(isles_l_o);
  724. if (isles_r_o)
  725. G_free(isles_r_o);
  726. if (isles_l_n)
  727. G_free(isles_l_n);
  728. if (isles_r_n)
  729. G_free(isles_r_n);
  730. return 1;
  731. }