build.c 30 KB

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