build.c 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312
  1. /*!
  2. \file lib/vector/Vlib/build.c
  3. \brief Vector library - Building topology
  4. Higher level functions for reading/writing/manipulating vectors.
  5. (C) 2001-2010, 2012-2013 by the GRASS Development Team
  6. This program is free software under the GNU General Public License
  7. (>=v2). Read the file COPYING that comes with GRASS for details.
  8. \author Original author CERL, probably Dave Gerdes or Mike Higgins.
  9. \author Update to GRASS 5.7 Radim Blazek and David D. Gray.
  10. */
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <stdarg.h>
  14. #include <unistd.h>
  15. #include <math.h>
  16. #include <grass/vector.h>
  17. #include <grass/glocale.h>
  18. #include "local_proto.h"
  19. #ifdef HAVE_POSTGRES
  20. #include "pg_local_proto.h"
  21. #endif
  22. #define SEP "-----------------------------------\n"
  23. #if !defined HAVE_OGR || !defined HAVE_POSTGRES
  24. static int format()
  25. {
  26. G_fatal_error(_("Requested format is not compiled in this version"));
  27. return 0;
  28. }
  29. #endif
  30. static int (*Build_array[]) () = {
  31. Vect_build_nat
  32. #ifdef HAVE_OGR
  33. , Vect_build_ogr
  34. , Vect_build_ogr
  35. #else
  36. , format
  37. , format
  38. #endif
  39. #ifdef HAVE_POSTGRES
  40. , Vect_build_pg
  41. #else
  42. , format
  43. #endif
  44. };
  45. /* for qsort */
  46. typedef struct {
  47. int i;
  48. double size;
  49. struct bound_box box;
  50. } BOX_SIZE;
  51. /*!
  52. \brief Build area on given side of line (GV_LEFT or GV_RIGHT)
  53. \param Map pointer to Map_info structure
  54. \param iline line id
  55. \param side side (GV_LEFT or GV_RIGHT)
  56. \return > 0 area id
  57. \return < 0 isle id
  58. \return 0 not created (may also already exist)
  59. */
  60. int Vect_build_line_area(struct Map_info *Map, int iline, int side)
  61. {
  62. int area, isle, n_lines;
  63. struct Plus_head *plus;
  64. struct bound_box box;
  65. static struct line_pnts *APoints = NULL;
  66. plus_t *lines;
  67. double area_size;
  68. plus = &(Map->plus);
  69. G_debug(3, "Vect_build_line_area() line = %d, side = %d", iline, side);
  70. if (!APoints)
  71. APoints = Vect_new_line_struct();
  72. /* get area */
  73. area = dig_line_get_area(plus, iline, side);
  74. if (area != 0) {
  75. /* -> there is already an area on this side of the line, skip */
  76. G_debug(3, " area/isle = %d -> skip", area);
  77. return 0;
  78. }
  79. /* build an area with this line */
  80. n_lines = dig_build_area_with_line(plus, iline, side, &lines);
  81. G_debug(3, " n_lines = %d", n_lines);
  82. if (n_lines < 1) {
  83. G_debug(3, " unable to build area with line %d", iline);
  84. return 0;
  85. } /* area was not built */
  86. /* get line points which forms a boundary of an area */
  87. Vect__get_area_points(Map, lines, n_lines, APoints);
  88. dig_line_box(APoints, &box);
  89. Vect_line_prune(APoints);
  90. if (APoints->n_points < 4) {
  91. G_warning(_("Area of size = 0.0 (less than 4 vertices) ignored"));
  92. return 0;
  93. }
  94. /* Area or island ? */
  95. dig_find_area_poly(APoints, &area_size);
  96. /* area_size = dig_find_poly_orientation(APoints); */
  97. /* area_size is not real area size, we are only interested in the sign */
  98. G_debug(3, " area/isle size = %f", area_size);
  99. if (area_size > 0) { /* CW: area */
  100. /* add area structure to plus */
  101. area = dig_add_area(plus, n_lines, lines, &box);
  102. if (area == -1) { /* error */
  103. G_fatal_error(_("Unable to add area (map closed, topo saved)"));
  104. }
  105. G_debug(3, " -> area %d", area);
  106. return area;
  107. }
  108. else if (area_size < 0) { /* CCW: island */
  109. isle = dig_add_isle(plus, n_lines, lines, &box);
  110. if (isle == -1) { /* error */
  111. G_fatal_error(_("Unable to add isle (map closed, topo saved)"));
  112. }
  113. G_debug(3, " -> isle %d", isle);
  114. return -isle;
  115. }
  116. else {
  117. /* TODO: What to do with such areas? Should be areas/isles of size 0 stored,
  118. * so that may be found and cleaned by some utility
  119. * Note: it would be useful for vertical closed polygons, but such would be added twice
  120. * as area */
  121. G_warning(_("Area of size = 0.0 ignored"));
  122. }
  123. return 0;
  124. }
  125. /* qsort areas by size */
  126. static int sort_by_size(const void *a, const void *b)
  127. {
  128. BOX_SIZE *as = (BOX_SIZE *)a;
  129. BOX_SIZE *bs = (BOX_SIZE *)b;
  130. if (as->size < bs->size)
  131. return -1;
  132. return (as->size > bs->size);
  133. }
  134. /*!
  135. \brief Find area outside island
  136. \param Map vector map
  137. \param isle isle id
  138. \param box isle bbox
  139. \return area id
  140. \return 0 if not found
  141. */
  142. int Vect_isle_find_area(struct Map_info *Map, int isle, const struct bound_box *box)
  143. {
  144. int i, j, line, sel_area, area, poly;
  145. const struct Plus_head *plus;
  146. struct P_line *Line;
  147. struct P_node *Node;
  148. struct P_isle *Isle;
  149. struct P_area *Area;
  150. struct P_topo_b *topo;
  151. struct bound_box *abox, nbox;
  152. static struct boxlist *List = NULL;
  153. static BOX_SIZE *size_list;
  154. static int alloc_size_list = 0;
  155. /* see also Vect_find_area() */
  156. /* Note: We should check all isle points (at least) because if topology is not clean
  157. * and two areas overlap, isle which is not completely within area may be attached,
  158. * but it would take long time */
  159. G_debug(3, "Vect_isle_find_area () island = %d", isle);
  160. plus = &(Map->plus);
  161. if (plus->Isle[isle] == NULL) {
  162. G_warning(_("Request to find area outside nonexistent isle"));
  163. return 0;
  164. }
  165. if (!List) {
  166. List = Vect_new_boxlist(1);
  167. alloc_size_list = 10;
  168. size_list = G_malloc(alloc_size_list * sizeof(BOX_SIZE));
  169. }
  170. Isle = plus->Isle[isle];
  171. line = abs(Isle->lines[0]);
  172. Line = plus->Line[line];
  173. topo = (struct P_topo_b *)Line->topo;
  174. Node = plus->Node[topo->N1];
  175. /* select areas by box */
  176. nbox.E = Node->x;
  177. nbox.W = Node->x;
  178. nbox.N = Node->y;
  179. nbox.S = Node->y;
  180. nbox.T = PORT_DOUBLE_MAX;
  181. nbox.B = -PORT_DOUBLE_MAX;
  182. Vect_select_areas_by_box(Map, &nbox, List);
  183. G_debug(3, "%d areas overlap island boundary point", List->n_values);
  184. /* sort areas by bbox size
  185. * get the smallest area that contains the isle
  186. * using the bbox size is working because if 2 areas both contain
  187. * the isle, one of these areas must be inside the other area
  188. * which means that the bbox of the outer area must be larger than
  189. * the bbox of the inner area, and equal bbox sizes are not possible */
  190. if (alloc_size_list < List->n_values) {
  191. alloc_size_list = List->n_values;
  192. size_list = G_realloc(size_list, alloc_size_list * sizeof(BOX_SIZE));
  193. }
  194. j = 0;
  195. for (i = 0; i < List->n_values; i++) {
  196. abox = &List->box[i];
  197. if (box->E > abox->E || box->W < abox->W || box->N > abox->N ||
  198. box->S < abox->S) {
  199. G_debug(3, " isle not completely inside area box");
  200. continue;
  201. }
  202. List->id[j] = List->id[i];
  203. List->box[j] = List->box[i];
  204. size_list[j].i = List->id[j];
  205. size_list[j].box = List->box[j];
  206. size_list[j].size = (abox->N - abox->S) * (abox->E - abox->W);
  207. j++;
  208. }
  209. List->n_values = j;
  210. if (List->n_values > 1) {
  211. if (List->n_values == 2) {
  212. /* simple swap */
  213. if (size_list[1].size < size_list[0].size) {
  214. size_list[0].i = List->id[1];
  215. size_list[1].i = List->id[0];
  216. size_list[0].box = List->box[1];
  217. size_list[1].box = List->box[0];
  218. }
  219. }
  220. else
  221. qsort(size_list, List->n_values, sizeof(BOX_SIZE), sort_by_size);
  222. }
  223. sel_area = 0;
  224. for (i = 0; i < List->n_values; i++) {
  225. area = size_list[i].i;
  226. G_debug(3, "area = %d", area);
  227. Area = plus->Area[area];
  228. /* Before other tests, simply exclude those areas inside isolated isles formed by one boundary */
  229. if (abs(Isle->lines[0]) == abs(Area->lines[0])) {
  230. G_debug(3, " area inside isolated isle");
  231. continue;
  232. }
  233. /* Check box */
  234. /* Note: If build is run on large files of areas imported from nontopo format (shapefile)
  235. * attaching of isles takes very long time because each area is also isle and select by
  236. * box all overlapping areas selects all areas with box overlapping first node.
  237. * Then reading coordinates for all those areas would take a long time -> check first
  238. * if isle's box is completely within area box */
  239. abox = &size_list[i].box;
  240. if (box->E > abox->E || box->W < abox->W || box->N > abox->N ||
  241. box->S < abox->S) {
  242. G_debug(3, " isle not completely inside area box");
  243. continue;
  244. }
  245. poly = Vect_point_in_area_outer_ring(Node->x, Node->y, Map, area, abox);
  246. G_debug(3, " poly = %d", poly);
  247. if (poly == 1) { /* point in area, but node is not part of area inside isle (would be poly == 2) */
  248. #if 1
  249. /* new version */
  250. /* the bounding box of the smaller area is
  251. * 1) inside the bounding box of a larger area and thus
  252. * 2) smaller than the bounding box of a larger area */
  253. sel_area = area;
  254. break;
  255. #else
  256. /* old version */
  257. /* In rare case island is inside more areas in that case we have to calculate area
  258. * of outer ring and take the smaller */
  259. if (sel_area == 0) { /* first */
  260. sel_area = area;
  261. }
  262. else { /* is not first */
  263. G_debug(1, "slow version of Vect_isle_find_area()");
  264. if (cur_size < 0) { /* second area */
  265. /* This is slow, but should not be called often */
  266. Vect_get_area_points(Map, sel_area, APoints);
  267. /* G_begin_polygon_area_calculations();
  268. cur_size =
  269. G_area_of_polygon(APoints->x, APoints->y,
  270. APoints->n_points); */
  271. /* this is faster, but there may be latlon problems: the poles */
  272. dig_find_area_poly(APoints, &cur_size);
  273. G_debug(3, " first area size = %f (n points = %d)",
  274. cur_size, APoints->n_points);
  275. }
  276. Vect_get_area_points(Map, area, APoints);
  277. /* size =
  278. G_area_of_polygon(APoints->x, APoints->y,
  279. APoints->n_points); */
  280. /* this is faster, but there may be latlon problems: the poles */
  281. dig_find_area_poly(APoints, &size);
  282. G_debug(3, " area size = %f (n points = %d)", size,
  283. APoints->n_points);
  284. if (size > 0 && size < cur_size) {
  285. sel_area = area;
  286. cur_size = size;
  287. /* this can not happen because the first area must be
  288. * inside the second area because the node
  289. * is inside both areas */
  290. G_warning(_("Larger bbox but smaller area!!!"));
  291. }
  292. }
  293. G_debug(3, "sel_area = %d cur_size = %f", sel_area, cur_size);
  294. #endif
  295. }
  296. }
  297. if (sel_area > 0) {
  298. G_debug(3, "Island %d in area %d", isle, sel_area);
  299. }
  300. else {
  301. G_debug(3, "Island %d is not in area", isle);
  302. }
  303. return sel_area;
  304. }
  305. /*!
  306. \brief (Re)Attach isle to area
  307. \param Map vector map
  308. \param isle isle id
  309. \param box isle bbox
  310. \return 0
  311. */
  312. int Vect_attach_isle(struct Map_info *Map, int isle, const struct bound_box *box)
  313. {
  314. int area;
  315. struct P_isle *Isle;
  316. struct Plus_head *plus;
  317. /* Note!: If topology is not clean and areas overlap, one island
  318. may fall to more areas (partially or fully). Before isle is
  319. attached to area it must be check if it is not attached yet */
  320. G_debug(3, "Vect_attach_isle(): isle = %d", isle);
  321. plus = &(Map->plus);
  322. area = Vect_isle_find_area(Map, isle, box);
  323. G_debug(3, "\tisle = %d -> area outside = %d", isle, area);
  324. if (area > 0) {
  325. Isle = plus->Isle[isle];
  326. if (Isle->area > 0) {
  327. G_debug(3, "Attempt to attach isle %d to more areas "
  328. "(=>topology is not clean)", isle);
  329. }
  330. else {
  331. Isle->area = area;
  332. dig_area_add_isle(plus, area, isle);
  333. }
  334. }
  335. return 0;
  336. }
  337. /*!
  338. \brief (Re)Attach isles in given bounding box to areas
  339. The warning for Vect_attach_centroids() applies here as well
  340. \param Map vector map
  341. \param box bounding box
  342. \return 0
  343. */
  344. int Vect_attach_isles(struct Map_info *Map, const struct bound_box *box)
  345. {
  346. int i, isle, area;
  347. struct bound_box abox;
  348. static struct boxlist *List = NULL;
  349. struct Plus_head *plus;
  350. G_debug(3, "Vect_attach_isles()");
  351. plus = &(Map->plus);
  352. if (!List)
  353. List = Vect_new_boxlist(TRUE);
  354. Vect_select_isles_by_box(Map, box, List);
  355. G_debug(3, " number of isles to attach = %d", List->n_values);
  356. for (i = 0; i < List->n_values; i++) {
  357. isle = List->id[i];
  358. area = plus->Isle[isle]->area;
  359. if (area > 0) {
  360. /* if the area box is not fully inside the box, detach
  361. * this might detach more than needed,
  362. * but all that need to be reattached and
  363. * is faster than reattaching all */
  364. Vect_get_area_box(Map, area, &abox);
  365. if (box->W < abox.W && box->E > abox.E &&
  366. box->S < abox.S && box->N > abox.N) {
  367. G_debug(3, "Outer area is fully inside search box");
  368. }
  369. else {
  370. dig_area_del_isle(plus, area, isle);
  371. plus->Isle[isle]->area = 0;
  372. area = 0;
  373. }
  374. }
  375. if (area == 0)
  376. Vect_attach_isle(Map, isle, &List->box[i]);
  377. }
  378. return 0;
  379. }
  380. /*!
  381. \brief (Re)Attach centroids in given bounding box to areas
  382. Warning: If map is updated on level2, it may happen that
  383. previously correct island becomes incorrect. In that case,
  384. centroid of area forming the island is reattached to outer area,
  385. because island polygon is not excluded.
  386. <pre>
  387. +-----------+ +-----------+
  388. | 1 | | 1 |
  389. | +---+---+ | | +---+---+ |
  390. | | 2 | 3 | | | | 2 | |
  391. | | x | | | -> | | x | |
  392. | | | | | | | | |
  393. | +---+---+ | | +---+---+ |
  394. | | | |
  395. +-----------+ +-----------+
  396. centroid is centroid is
  397. attached to 2 reattached to 1
  398. </pre>
  399. Because of this, when the centroid is reattached to another area,
  400. it is always necessary to check if original area exist, unregister
  401. centroid from previous area. To simplify code, this is
  402. implemented so that centroid is always first unregistered and if
  403. new area is found, it is registered again.
  404. \param Map vector map
  405. \param box bounding box
  406. \return 0
  407. */
  408. int Vect_attach_centroids(struct Map_info *Map, const struct bound_box * box)
  409. {
  410. int i, area, centr;
  411. static int first = 1;
  412. struct bound_box abox;
  413. static struct boxlist *List;
  414. struct P_area *Area;
  415. struct P_line *Line;
  416. struct P_topo_c *topo;
  417. struct Plus_head *plus;
  418. G_debug(3, "Vect_attach_centroids()");
  419. plus = &(Map->plus);
  420. if (first) {
  421. List = Vect_new_boxlist(1);
  422. first = 0;
  423. }
  424. Vect_select_lines_by_box(Map, box, GV_CENTROID, List);
  425. G_debug(3, "\tnumber of centroids to reattach = %d", List->n_values);
  426. for (i = 0; i < List->n_values; i++) {
  427. centr = List->id[i];
  428. Line = plus->Line[centr];
  429. topo = (struct P_topo_c *)Line->topo;
  430. area = topo->area;
  431. if (area > 0) {
  432. /* if the area box is not fully inside the box, detach
  433. * this might detach more than needed,
  434. * but all that need to be reattached and
  435. * is faster than reattaching all */
  436. Vect_get_area_box(Map, area, &abox);
  437. if (box->W < abox.W && box->E > abox.E &&
  438. box->S < abox.S && box->N > abox.N) {
  439. G_debug(3, "Centroid's area is fully inside search box");
  440. }
  441. else {
  442. Area = plus->Area[area];
  443. Area->centroid = 0;
  444. topo->area = 0;
  445. area = 0;
  446. }
  447. }
  448. if (area > 0) {
  449. continue;
  450. }
  451. area = Vect_find_area(Map, List->box[i].E, List->box[i].N);
  452. G_debug(3, "\tcentroid %d is in area %d", centr, area);
  453. if (area > 0) {
  454. Area = plus->Area[area];
  455. if (Area->centroid == 0) { /* first centroid */
  456. G_debug(3, "\tfirst centroid -> attach to area");
  457. Area->centroid = centr;
  458. topo->area = area;
  459. }
  460. else if (Area->centroid != centr) { /* duplicate centroid */
  461. /* Note: it cannot happen that Area->centroid == centr, because the centroid
  462. * was not registered or a duplicate */
  463. G_debug(3, "\tduplicate centroid -> do not attach to area");
  464. topo->area = -area;
  465. }
  466. }
  467. }
  468. return 0;
  469. }
  470. /*!
  471. \brief Build topology for vector map
  472. \param Map vector map
  473. \return 1 on success
  474. \return 0 on error
  475. */
  476. int Vect_build(struct Map_info *Map)
  477. {
  478. return Vect_build_partial(Map, GV_BUILD_ALL);
  479. }
  480. /*!
  481. \brief Extensive tests for correct topology
  482. - lines or boundaries of zero length
  483. - intersecting boundaries, ie. overlapping areas
  484. - areas without centroids that are not isles
  485. \param Map vector map
  486. \param[out] Err vector map where errors will be written or NULL
  487. \return 1 on success
  488. \return 0 on error
  489. */
  490. int Vect_topo_check(struct Map_info *Map, struct Map_info *Err)
  491. {
  492. int line, nlines;
  493. int nerrors, n_zero_lines, n_zero_boundaries;
  494. struct line_pnts *Points;
  495. struct line_cats *Cats;
  496. /* rebuild topology if needed */
  497. if (Vect_get_built(Map) != GV_BUILD_ALL) {
  498. Vect_build_partial(Map, GV_BUILD_NONE);
  499. Vect_build(Map);
  500. }
  501. G_message(_("Checking for topological errors..."));
  502. Points = Vect_new_line_struct();
  503. Cats = Vect_new_cats_struct();
  504. /* lines or boundaries of zero length */
  505. n_zero_lines = n_zero_boundaries = 0;
  506. nlines = Vect_get_num_lines(Map);
  507. for (line = 1; line <= nlines; line++) {
  508. int type;
  509. if (!Vect_line_alive(Map, line))
  510. continue;
  511. type = Vect_get_line_type(Map, line);
  512. if (type & GV_LINES) {
  513. double len;
  514. Vect_read_line(Map, Points, Cats, line);
  515. len = Vect_line_length(Points);
  516. if (len == 0) {
  517. if (type & GV_LINE)
  518. n_zero_lines++;
  519. else if (type & GV_BOUNDARY)
  520. n_zero_boundaries++;
  521. if (Err)
  522. Vect_write_line(Err, type, Points, Cats);
  523. }
  524. }
  525. }
  526. if (n_zero_lines)
  527. G_warning(_("Number of lines of length zero: %d"), n_zero_lines);
  528. if (n_zero_boundaries)
  529. G_warning(_("Number of boundaries of length zero: %d"), n_zero_boundaries);
  530. /* remaining checks are for areas only */
  531. if (Vect_get_num_primitives(Map, GV_BOUNDARY) == 0)
  532. return 1;
  533. /* intersecting boundaries -> overlapping areas */
  534. nerrors = Vect_check_line_breaks(Map, GV_BOUNDARY, Err);
  535. if (nerrors)
  536. G_warning(_("Number of boundary intersections: %d"), nerrors);
  537. /* areas without centroids that are not isles
  538. * only makes sense if all boundaries are correct */
  539. nerrors = 0;
  540. for (line = 1; line <= nlines; line++) {
  541. int type;
  542. if (!Vect_line_alive(Map, line))
  543. continue;
  544. type = Vect_get_line_type(Map, line);
  545. if (type == GV_BOUNDARY) {
  546. struct P_topo_b *topo = (struct P_topo_b *)Map->plus.Line[line]->topo;
  547. if (topo->left == 0 || topo->right == 0) {
  548. G_debug(3, "line = %d left = %d right = %d", line,
  549. topo->left, topo->right);
  550. nerrors++;
  551. }
  552. }
  553. }
  554. if (nerrors)
  555. G_warning(_("Skipping further checks because of incorrect boundaries"));
  556. else {
  557. int i, area, left, right, neighbour;
  558. int nareas = Vect_get_num_areas(Map);
  559. struct ilist *List = Vect_new_list();
  560. nerrors = 0;
  561. for (area = 1; area <= nareas; area++) {
  562. if (!Vect_area_alive(Map, area))
  563. continue;
  564. line = Vect_get_area_centroid(Map, area);
  565. if (line != 0)
  566. continue; /* has centroid */
  567. Vect_get_area_boundaries(Map, area, List);
  568. for (i = 0; i < List->n_values; i++) {
  569. line = List->value[i];
  570. Vect_get_line_areas(Map, abs(line), &left, &right);
  571. if (line > 0)
  572. neighbour = left;
  573. else
  574. neighbour = right;
  575. if (neighbour < 0) {
  576. neighbour = Vect_get_isle_area(Map, abs(neighbour));
  577. if (!neighbour) {
  578. /* borders outer void */
  579. nerrors++;
  580. if (Err) {
  581. Vect_read_line(Map, Points, Cats, abs(line));
  582. Vect_write_line(Err, GV_BOUNDARY, Points, Cats);
  583. }
  584. }
  585. /* else neighbour is > 0, check below */
  586. }
  587. if (neighbour > 0) {
  588. if (Vect_get_area_centroid(Map, neighbour) == 0) {
  589. /* neighbouring area does not have a centroid either */
  590. nerrors++;
  591. if (Err) {
  592. Vect_read_line(Map, Points, Cats, abs(line));
  593. Vect_write_line(Err, GV_BOUNDARY, Points, Cats);
  594. }
  595. }
  596. }
  597. }
  598. }
  599. Vect_destroy_list(List);
  600. if (nerrors)
  601. G_warning(_("Number of redundant holes: %d"),
  602. nerrors);
  603. }
  604. /* what else ? */
  605. Vect_destroy_line_struct(Points);
  606. Vect_destroy_cats_struct(Cats);
  607. return 1;
  608. }
  609. /*!
  610. \brief Return current highest built level (part)
  611. \param Map vector map
  612. \return current highest built level
  613. */
  614. int Vect_get_built(const struct Map_info *Map)
  615. {
  616. return Map->plus.built;
  617. }
  618. /*!
  619. \brief Downgrade build level (for internal use only)
  620. See Vect_build_nat(), Vect__build_sfa(), and Vect_build_pg() for
  621. implementation issues.
  622. \param Map pointer to Map_info
  623. \param build
  624. */
  625. void Vect__build_downgrade(struct Map_info *Map, int build)
  626. {
  627. int line;
  628. struct Plus_head *plus;
  629. struct P_line *Line;
  630. plus = &(Map->plus);
  631. /* lower level request - release old sources (this also
  632. initializes structures and numbers of elements) */
  633. if (plus->built >= GV_BUILD_CENTROIDS && build < GV_BUILD_CENTROIDS) {
  634. /* reset info about areas stored for centroids */
  635. for (line = 1; line <= plus->n_lines; line++) {
  636. Line = plus->Line[line];
  637. if (Line && Line->type == GV_CENTROID) {
  638. struct P_topo_c *topo = (struct P_topo_c *)Line->topo;
  639. topo->area = 0;
  640. }
  641. }
  642. dig_free_plus_areas(plus);
  643. dig_spidx_free_areas(plus);
  644. dig_free_plus_isles(plus);
  645. dig_spidx_free_isles(plus);
  646. }
  647. if (plus->built >= GV_BUILD_AREAS && build < GV_BUILD_AREAS) {
  648. /* reset info about areas stored for lines */
  649. for (line = 1; line <= plus->n_lines; line++) {
  650. Line = plus->Line[line];
  651. if (Line && Line->type == GV_BOUNDARY) {
  652. struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
  653. topo->left = 0;
  654. topo->right = 0;
  655. }
  656. }
  657. dig_free_plus_areas(plus);
  658. dig_spidx_free_areas(plus);
  659. dig_free_plus_isles(plus);
  660. dig_spidx_free_isles(plus);
  661. }
  662. if (plus->built >= GV_BUILD_BASE && build < GV_BUILD_BASE) {
  663. dig_free_plus_nodes(plus);
  664. dig_spidx_free_nodes(plus);
  665. dig_free_plus_lines(plus);
  666. dig_spidx_free_lines(plus);
  667. }
  668. plus->built = build;
  669. }
  670. /*!
  671. \brief Build partial topology for vector map.
  672. Should only be used in special cases of vector processing.
  673. This functions optionally builds only some parts of
  674. topology. Highest level is specified by build parameter which may
  675. be:
  676. - GV_BUILD_NONE - nothing is build
  677. - GV_BUILD_BASE - basic topology, nodes, lines, spatial index;
  678. - GV_BUILD_AREAS - build areas and islands, but islands are not attached to areas;
  679. - GV_BUILD_ATTACH_ISLES - attach islands to areas;
  680. - GV_BUILD_CENTROIDS - assign centroids to areas, build category index;
  681. - GV_BUILD_ALL - top level, the same as GV_BUILD_CENTROIDS.
  682. If functions is called with build lower than current value of the
  683. Map, the level is downgraded to requested value.
  684. All calls to Vect_write_line(), Vect_rewrite_line(),
  685. Vect_delete_line() respect the last value of build used in this
  686. function.
  687. Note that the functions has effect only if requested level is
  688. higher than current level, to rebuild part of topology, call first
  689. downgrade and then upgrade, for example:
  690. - Vect_build()
  691. - Vect_build_partial(,GV_BUILD_BASE,)
  692. - Vect_build_partial(,GV_BUILD_AREAS,)
  693. \param Map vector map
  694. \param build highest level of build
  695. \return 1 on success
  696. \return 0 on error
  697. */
  698. int Vect_build_partial(struct Map_info *Map, int build)
  699. {
  700. struct Plus_head *plus;
  701. int ret;
  702. G_debug(3, "Vect_build(): build = %d", build);
  703. /* If topology is already build (map on > level 2), set level to 1
  704. * so that lines will be read by V1_read_ (all lines) */
  705. Map->level = LEVEL_1; /* may be not needed, because V1_read is used
  706. directly by Vect_build_ */
  707. if (Map->format != GV_FORMAT_OGR_DIRECT &&
  708. !(Map->format == GV_FORMAT_POSTGIS && Map->fInfo.pg.toposchema_name))
  709. /* don't write support files for OGR direct and PostGIS Topology */
  710. Map->support_updated = TRUE;
  711. if (!Map->plus.Spidx_built) {
  712. if (Vect_open_sidx(Map, 2) < 0)
  713. G_fatal_error(_("Unable to open spatial index file for vector map <%s>"),
  714. Vect_get_full_name(Map));
  715. }
  716. plus = &(Map->plus);
  717. if (build > GV_BUILD_NONE && !Map->temporary && Map->format != GV_FORMAT_POSTGIS) {
  718. G_message(_("Building topology for vector map <%s>..."),
  719. Vect_get_full_name(Map));
  720. }
  721. plus->with_z = Map->head.with_z;
  722. plus->spidx_with_z = Map->head.with_z;
  723. if (build == GV_BUILD_ALL && plus->built < GV_BUILD_ALL) {
  724. dig_cidx_free(plus); /* free old (if any) category index */
  725. dig_cidx_init(plus);
  726. }
  727. ret = ((*Build_array[Map->format]) (Map, build));
  728. if (ret == 0) {
  729. return 0;
  730. }
  731. if (build > GV_BUILD_NONE) {
  732. Map->level = LEVEL_2;
  733. G_verbose_message(_("Topology was built"));
  734. }
  735. plus->mode = GV_MODE_WRITE;
  736. if (build == GV_BUILD_ALL) {
  737. plus->cidx_up_to_date = TRUE; /* category index was build */
  738. dig_cidx_sort(plus);
  739. }
  740. if (build > GV_BUILD_NONE) {
  741. G_verbose_message(_("Number of nodes: %d"), plus->n_nodes);
  742. G_verbose_message(_("Number of primitives: %d"), plus->n_lines);
  743. G_verbose_message(_("Number of points: %d"), plus->n_plines);
  744. G_verbose_message(_("Number of lines: %d"), plus->n_llines);
  745. G_verbose_message(_("Number of boundaries: %d"), plus->n_blines);
  746. G_verbose_message(_("Number of centroids: %d"), plus->n_clines);
  747. if (plus->n_flines > 0)
  748. G_verbose_message(_("Number of faces: %d"), plus->n_flines);
  749. if (plus->n_klines > 0)
  750. G_verbose_message(_("Number of kernels: %d"), plus->n_klines);
  751. }
  752. if (plus->built >= GV_BUILD_AREAS) {
  753. int line, nlines, area, nareas, err_boundaries, err_centr_out,
  754. err_centr_dupl, err_nocentr;
  755. struct P_line *Line;
  756. struct Plus_head *Plus;
  757. /* Count errors (it does not take much time comparing to build process) */
  758. Plus = &(Map->plus);
  759. nlines = Vect_get_num_lines(Map);
  760. err_boundaries = err_centr_out = err_centr_dupl = 0;
  761. for (line = 1; line <= nlines; line++) {
  762. Line = Plus->Line[line];
  763. if (!Line)
  764. continue;
  765. if (Line->type == GV_BOUNDARY) {
  766. struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
  767. if (topo->left == 0 || topo->right == 0) {
  768. G_debug(3, "line = %d left = %d right = %d", line,
  769. topo->left, topo->right);
  770. err_boundaries++;
  771. }
  772. }
  773. if (Line->type == GV_CENTROID) {
  774. struct P_topo_c *topo = (struct P_topo_c *)Line->topo;
  775. if (topo->area == 0)
  776. err_centr_out++;
  777. else if (topo->area < 0)
  778. err_centr_dupl++;
  779. }
  780. }
  781. err_nocentr = 0;
  782. nareas = Vect_get_num_areas(Map);
  783. for (area = 1; area <= nareas; area++) {
  784. if (!Vect_area_alive(Map, area))
  785. continue;
  786. line = Vect_get_area_centroid(Map, area);
  787. if (line == 0)
  788. err_nocentr++;
  789. }
  790. G_verbose_message(_("Number of areas: %d"), plus->n_areas);
  791. G_verbose_message(_("Number of isles: %d"), plus->n_isles);
  792. #if 0
  793. /* not an error, message disabled to avoid confusion */
  794. if (err_nocentr)
  795. G_message(_("Number of areas without centroid: %d"),
  796. err_nocentr);
  797. #endif
  798. if (plus->n_clines > plus->n_areas)
  799. G_warning(_("Number of centroids exceeds number of areas: %d > %d"),
  800. plus->n_clines, plus->n_areas);
  801. if (err_boundaries)
  802. G_warning(_("Number of incorrect boundaries: %d"),
  803. err_boundaries);
  804. if (err_centr_out)
  805. G_warning(_("Number of centroids outside area: %d"),
  806. err_centr_out);
  807. if (err_centr_dupl)
  808. G_warning(_("Number of duplicate centroids: %d"), err_centr_dupl);
  809. }
  810. else if (build > GV_BUILD_NONE) {
  811. G_verbose_message(_("Number of areas: -"));
  812. G_verbose_message(_("Number of isles: -"));
  813. }
  814. return 1;
  815. }
  816. /*!
  817. \brief Save topology file for vector map
  818. \param Map pointer to Map_info structure
  819. \return 1 on success
  820. \return 0 on error
  821. */
  822. int Vect_save_topo(struct Map_info *Map)
  823. {
  824. struct Plus_head *plus;
  825. char path[GPATH_MAX];
  826. struct gvfile fp;
  827. G_debug(1, "Vect_save_topo()");
  828. /* write out all the accumulated info to the plus file */
  829. plus = &(Map->plus);
  830. dig_file_init(&fp);
  831. Vect__get_path(path, Map);
  832. fp.file = G_fopen_new(path, GV_TOPO_ELEMENT);
  833. if (fp.file == NULL) {
  834. G_warning(_("Unable to create topo file for vector map <%s>"), Map->name);
  835. return 0;
  836. }
  837. /* set portable info */
  838. dig_init_portable(&(plus->port), dig__byte_order_out());
  839. if (0 > dig_write_plus_file(&fp, plus)) {
  840. G_warning(_("Error writing out topo file"));
  841. return 0;
  842. }
  843. fclose(fp.file);
  844. return 1;
  845. }
  846. /*!
  847. \brief Dump topology to file
  848. \param Map vector map
  849. \param out file for output (stdout/stderr for example)
  850. \return 1 on success
  851. \return 0 on error
  852. */
  853. int Vect_topo_dump(const struct Map_info *Map, FILE *out)
  854. {
  855. int i, j, line, isle;
  856. float angle_deg;
  857. struct P_node *Node;
  858. struct P_line *Line;
  859. struct P_area *Area;
  860. struct P_isle *Isle;
  861. struct bound_box box;
  862. const struct Plus_head *plus;
  863. plus = &(Map->plus);
  864. fprintf(out, "---------- TOPOLOGY DUMP ----------\n");
  865. fprintf(out, "Map: %s\n", Vect_get_full_name(Map));
  866. fprintf(out, "Topology format: ");
  867. if (Map->format == GV_FORMAT_NATIVE)
  868. fprintf(out, "native");
  869. else if (Map->format == GV_FORMAT_POSTGIS &&
  870. Map->fInfo.pg.toposchema_name) {
  871. fprintf(out, "PostGIS");
  872. }
  873. else {
  874. fprintf(out, "pseudo (simple features)");
  875. if (Map->format == GV_FORMAT_OGR)
  876. fprintf(out, " @ OGR");
  877. else
  878. fprintf(out, " @ PostgreSQL");
  879. }
  880. fprintf(out, "\n");
  881. fprintf(out, SEP);
  882. /* box */
  883. Vect_box_copy(&box, &(plus->box));
  884. fprintf(out, "N,S,E,W,T,B: %f, %f, %f, %f, %f, %f\n", box.N, box.S,
  885. box.E, box.W, box.T, box.B);
  886. fprintf(out, SEP);
  887. /* nodes */
  888. fprintf(out, "Nodes (%d nodes, alive + dead):\n", plus->n_nodes);
  889. for (i = 1; i <= plus->n_nodes; i++) {
  890. if (plus->Node[i] == NULL) {
  891. continue;
  892. }
  893. Node = plus->Node[i];
  894. fprintf(out, "node = %d, n_lines = %d, xyz = %f, %f, %f\n", i,
  895. Node->n_lines, Node->x, Node->y, Node->z);
  896. for (j = 0; j < Node->n_lines; j++) {
  897. line = Node->lines[j];
  898. Line = plus->Line[abs(line)];
  899. angle_deg = (Node->angles[j] * 180) / M_PI;
  900. if (angle_deg < 0)
  901. angle_deg += 360;
  902. fprintf(out, " line = %3d, type = %d, angle = %f (%.4f)\n", line,
  903. Line->type, Node->angles[j], angle_deg);
  904. }
  905. }
  906. fprintf(out, SEP);
  907. /* lines */
  908. fprintf(out, "Lines (%d lines, alive + dead):\n", plus->n_lines);
  909. for (i = 1; i <= plus->n_lines; i++) {
  910. if (plus->Line[i] == NULL) {
  911. continue;
  912. }
  913. Line = plus->Line[i];
  914. if (Line->type == GV_POINT) {
  915. fprintf(out, "line = %d, type = %d, offset = %lu\n",
  916. i, Line->type, (unsigned long)Line->offset);
  917. }
  918. else if (Line->type == GV_CENTROID) {
  919. struct P_topo_c *topo = (struct P_topo_c *)Line->topo;
  920. fprintf(out, "line = %d, type = %d, offset = %lu, area = %d\n",
  921. i, Line->type, (unsigned long)Line->offset, topo->area);
  922. }
  923. else if (Line->type == GV_LINE) {
  924. struct P_topo_l *topo = (struct P_topo_l *)Line->topo;
  925. fprintf(out, "line = %d, type = %d, offset = %lu, n1 = %d, n2 = %d\n",
  926. i, Line->type, (unsigned long)Line->offset, topo->N1,
  927. topo->N2);
  928. }
  929. else if (Line->type == GV_BOUNDARY) {
  930. struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
  931. fprintf(out, "line = %d, type = %d, offset = %lu, n1 = %d, n2 = %d, "
  932. "left = %d, right = %d\n",
  933. i, Line->type, (unsigned long)Line->offset, topo->N1,
  934. topo->N2, topo->left, topo->right);
  935. }
  936. else if (Line->type == GV_FACE) {
  937. struct P_topo_f *topo = (struct P_topo_f *)Line->topo;
  938. fprintf(out, "line = %d, type = %d, offset = %lu, e1 = %d, e2 = %d, "
  939. "e3 = %d, left = %d, right = %d\n",
  940. i, Line->type, (unsigned long)Line->offset, topo->E[0],
  941. topo->E[1], topo->E[2], topo->left, topo->right);
  942. }
  943. else if (Line->type == GV_KERNEL) {
  944. struct P_topo_k *topo = (struct P_topo_k *)Line->topo;
  945. fprintf(out, "line = %d, type = %d, offset = %lu, volume = %d",
  946. i, Line->type, (unsigned long)Line->offset, topo->volume);
  947. }
  948. }
  949. fprintf(out, SEP);
  950. /* areas */
  951. fprintf(out, "Areas (%d areas, alive + dead):\n", plus->n_areas);
  952. for (i = 1; i <= plus->n_areas; i++) {
  953. if (plus->Area[i] == NULL) {
  954. continue;
  955. }
  956. Area = plus->Area[i];
  957. fprintf(out, "area = %d, n_lines = %d, n_isles = %d centroid = %d\n",
  958. i, Area->n_lines, Area->n_isles, Area->centroid);
  959. for (j = 0; j < Area->n_lines; j++) {
  960. line = Area->lines[j];
  961. Line = plus->Line[abs(line)];
  962. fprintf(out, " line = %3d\n", line);
  963. }
  964. for (j = 0; j < Area->n_isles; j++) {
  965. isle = Area->isles[j];
  966. fprintf(out, " isle = %3d\n", isle);
  967. }
  968. }
  969. fprintf(out, SEP);
  970. /* isles */
  971. fprintf(out, "Islands (%d islands, alive + dead):\n", plus->n_isles);
  972. for (i = 1; i <= plus->n_isles; i++) {
  973. if (plus->Isle[i] == NULL) {
  974. continue;
  975. }
  976. Isle = plus->Isle[i];
  977. fprintf(out, "isle = %d, n_lines = %d area = %d\n", i, Isle->n_lines,
  978. Isle->area);
  979. for (j = 0; j < Isle->n_lines; j++) {
  980. line = Isle->lines[j];
  981. Line = plus->Line[abs(line)];
  982. fprintf(out, " line = %3d\n", line);
  983. }
  984. }
  985. return 1;
  986. }
  987. /*!
  988. \brief Create spatial index if necessary.
  989. To be used in modules.
  990. Map must be opened on level 2.
  991. \param[in,out] Map pointer to vector map
  992. \return 0 OK
  993. \return 1 error
  994. */
  995. int Vect_build_sidx(struct Map_info *Map)
  996. {
  997. if (Map->level < 2) {
  998. G_fatal_error(_("Unable to build spatial index from topology, "
  999. "vector map is not opened at topology level 2"));
  1000. }
  1001. if (!Map->plus.Spidx_built) {
  1002. return Vect_build_sidx_from_topo(Map);
  1003. }
  1004. return 0;
  1005. }
  1006. /*!
  1007. \brief Create spatial index from topology if necessary (not longer
  1008. supported)
  1009. \param Map pointer to vector map
  1010. \return 1
  1011. */
  1012. int Vect_build_sidx_from_topo(const struct Map_info *Map)
  1013. {
  1014. G_debug(3, "Vect_build_sidx_from_topo(): name=%s",
  1015. Vect_get_full_name(Map));
  1016. G_warning(_("%s is no longer supported"), "Vect_build_sidx_from_topo()");
  1017. return 1;
  1018. }
  1019. /*!
  1020. \brief Save spatial index file for vector map
  1021. \param Map vector map
  1022. \return 1 on success
  1023. \return 0 on error
  1024. */
  1025. int Vect_save_sidx(struct Map_info *Map)
  1026. {
  1027. struct Plus_head *plus;
  1028. char file_path[GPATH_MAX];
  1029. G_debug(1, "Vect_save_spatial_index()");
  1030. plus = &(Map->plus);
  1031. if (!plus->Spidx_built) {
  1032. G_warning(_("Spatial index not available, can not be saved"));
  1033. return 0;
  1034. }
  1035. /* new or update mode ? */
  1036. if (plus->Spidx_new == TRUE) {
  1037. /* write out rtrees to sidx file */
  1038. Vect__get_element_path(file_path, Map, GV_SIDX_ELEMENT);
  1039. G_debug(1, "Open sidx: %s", file_path);
  1040. dig_file_init(&(plus->spidx_fp));
  1041. plus->spidx_fp.file = fopen(file_path, "w+");
  1042. if (plus->spidx_fp.file == NULL) {
  1043. G_warning(_("Unable to create spatial index file for vector map <%s>"),
  1044. Vect_get_name(Map));
  1045. return 0;
  1046. }
  1047. /* set portable info */
  1048. dig_init_portable(&(plus->spidx_port), dig__byte_order_out());
  1049. if (0 > dig_Wr_spidx(&(plus->spidx_fp), plus)) {
  1050. G_warning(_("Error writing out spatial index file"));
  1051. return 0;
  1052. }
  1053. Map->plus.Spidx_new = FALSE;
  1054. }
  1055. fclose(Map->plus.spidx_fp.file);
  1056. Map->plus.Spidx_built = FALSE;
  1057. return 1;
  1058. }
  1059. /*!
  1060. \brief Dump spatial index to file
  1061. \param Map vector map
  1062. \param out file for output (stdout/stderr for example)
  1063. \return 1 on success
  1064. \return 0 on error
  1065. */
  1066. int Vect_sidx_dump(const struct Map_info *Map, FILE * out)
  1067. {
  1068. if (!(Map->plus.Spidx_built)) {
  1069. Vect_build_sidx_from_topo(Map);
  1070. }
  1071. fprintf(out, "---------- SPATIAL INDEX DUMP ----------\n");
  1072. dig_dump_spidx(out, &(Map->plus));
  1073. return 1;
  1074. }