build_sfa.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. /*!
  2. \file lib/vector/Vlib/build_sfa.c
  3. \brief Vector library - Building pseudo-topology for simple feature access
  4. Higher level functions for reading/writing/manipulating vectors.
  5. Line offset is
  6. - centroids : FID
  7. - other types : index of the first record (which is FID) in offset array.
  8. (C) 2001-2012 by the GRASS Development Team
  9. This program is free software under the GNU General Public License
  10. (>=v2). Read the file COPYING that comes with GRASS for details.
  11. \author Radim Blazek
  12. \author Piero Cavalieri
  13. \author Various updates for GRASS 7 by Martin Landa <landa.martin gmail.com>
  14. */
  15. #include <stdlib.h>
  16. #include <grass/gis.h>
  17. #include <grass/vector.h>
  18. #include <grass/glocale.h>
  19. /*!
  20. \brief This structure keeps info about geometry parts above current
  21. geometry, path to curent geometry in the feature. First 'part' number
  22. however is feature id */
  23. struct geom_parts
  24. {
  25. int *part;
  26. int a_parts;
  27. int n_parts;
  28. };
  29. static void init_parts(struct geom_parts *);
  30. static void reset_parts(struct geom_parts *);
  31. static void free_parts(struct geom_parts *);
  32. static void add_part(struct geom_parts *, int);
  33. static void del_part(struct geom_parts *);
  34. static void add_parts_to_offset(struct Format_info_offset *,
  35. struct geom_parts *);
  36. static int add_line(struct Plus_head *, struct Format_info_offset *,
  37. int, struct line_pnts *,
  38. int, struct geom_parts *);
  39. #ifdef HAVE_POSTGRES
  40. #include "pg_local_proto.h"
  41. static int add_geometry_pg(struct Plus_head *,
  42. struct Format_info_pg *,
  43. struct feat_parts *, int,
  44. int, int,
  45. struct geom_parts *);
  46. static void build_pg(struct Map_info *, int);
  47. #endif
  48. #ifdef HAVE_OGR
  49. #include <ogr_api.h>
  50. static int add_geometry_ogr(struct Plus_head *,
  51. struct Format_info_ogr *,
  52. OGRGeometryH, int, int,
  53. struct geom_parts *);
  54. static void build_ogr(struct Map_info *, int);
  55. #endif
  56. /*!
  57. \brief Init parts
  58. */
  59. void init_parts(struct geom_parts * parts)
  60. {
  61. G_zero(parts, sizeof(struct geom_parts));
  62. }
  63. /*!
  64. \brief Reset parts
  65. */
  66. void reset_parts(struct geom_parts * parts)
  67. {
  68. parts->n_parts = 0;
  69. }
  70. /*!
  71. \brief Free parts
  72. */
  73. void free_parts(struct geom_parts * parts)
  74. {
  75. G_free(parts->part);
  76. G_zero(parts, sizeof(struct geom_parts));
  77. }
  78. /*!
  79. \brief Add new part number to parts
  80. */
  81. void add_part(struct geom_parts *parts, int part)
  82. {
  83. if (parts->a_parts == parts->n_parts) {
  84. parts->a_parts += 10;
  85. parts->part = (int *) G_realloc((void *)parts->part,
  86. parts->a_parts * sizeof(int));
  87. }
  88. parts->part[parts->n_parts] = part;
  89. parts->n_parts++;
  90. }
  91. /*!
  92. \brief Remove last part
  93. */
  94. void del_part(struct geom_parts *parts)
  95. {
  96. parts->n_parts--;
  97. }
  98. /*!
  99. \brief Add parts to offset
  100. */
  101. void add_parts_to_offset(struct Format_info_offset *offset,
  102. struct geom_parts *parts)
  103. {
  104. int i, j;
  105. if (offset->array_num + parts->n_parts >= offset->array_alloc) {
  106. offset->array_alloc += parts->n_parts + 1000;
  107. offset->array = (int *)G_realloc(offset->array,
  108. offset->array_alloc * sizeof(int));
  109. }
  110. j = offset->array_num;
  111. for (i = 0; i < parts->n_parts; i++) {
  112. G_debug(4, "add offset %d", parts->part[i]);
  113. offset->array[j] = parts->part[i];
  114. j++;
  115. }
  116. offset->array_num += parts->n_parts;
  117. }
  118. /*!
  119. \brief Add line to support structures
  120. */
  121. int add_line(struct Plus_head *plus, struct Format_info_offset *offset,
  122. int type, struct line_pnts *Points,
  123. int FID, struct geom_parts *parts)
  124. {
  125. int line;
  126. long offset_value;
  127. struct bound_box box;
  128. if (type != GV_CENTROID) {
  129. /* beginning in the offset array */
  130. offset_value = offset->array_num;
  131. }
  132. else {
  133. /* TODO : could be used to statore category ? */
  134. /* because centroids are read from topology, not from layer */
  135. offset_value = FID;
  136. }
  137. G_debug(4, "Register line: FID = %d offset = %ld", FID, offset_value);
  138. dig_line_box(Points, &box);
  139. line = dig_add_line(plus, type, Points, &box, offset_value);
  140. G_debug(4, "Line registered with line = %d", line);
  141. /* Set box */
  142. if (line == 1)
  143. Vect_box_copy(&(plus->box), &box);
  144. else
  145. Vect_box_extend(&(plus->box), &box);
  146. if (type != GV_BOUNDARY) {
  147. dig_cidx_add_cat(plus, 1, (int)FID, line, type);
  148. }
  149. else {
  150. dig_cidx_add_cat(plus, 0, 0, line, type);
  151. }
  152. /* because centroids are read from topology, not from layer */
  153. if (type != GV_CENTROID)
  154. add_parts_to_offset(offset, parts);
  155. return line;
  156. }
  157. #ifdef HAVE_POSTGRES
  158. /*!
  159. \brief Recursively add geometry (PostGIS) to topology
  160. */
  161. int add_geometry_pg(struct Plus_head *plus,
  162. struct Format_info_pg *pg_info,
  163. struct feat_parts *fparts, int ipart,
  164. int FID, int build, struct geom_parts *parts)
  165. {
  166. int line, i, idx, area, isle, outer_area, ret;
  167. int lines[1];
  168. double area_size, x, y;
  169. SF_FeatureType ftype;
  170. struct bound_box box;
  171. struct Format_info_offset *offset;
  172. struct line_pnts *line_i;
  173. ftype = fparts->ftype[ipart];
  174. G_debug(4, "add_geometry_pg() FID = %d ftype = %d", FID, ftype);
  175. offset = &(pg_info->offset);
  176. outer_area = 0;
  177. switch(ftype) {
  178. case SF_POINT:
  179. G_debug(4, "Point");
  180. line_i = pg_info->cache.lines[fparts->idx[ipart]];
  181. add_line(plus, offset, GV_POINT, line_i,
  182. FID, parts);
  183. break;
  184. case SF_LINESTRING:
  185. G_debug(4, "LineString");
  186. line_i = pg_info->cache.lines[fparts->idx[ipart]];
  187. add_line(plus, offset, GV_LINE, line_i,
  188. FID, parts);
  189. break;
  190. case SF_POLYGON:
  191. G_debug(4, "Polygon");
  192. /* register boundaries */
  193. idx = fparts->idx[ipart];
  194. for (i = 0; i < fparts->nlines[ipart]; i++) {
  195. line_i = pg_info->cache.lines[idx++];
  196. add_part(parts, i);
  197. line = add_line(plus, offset, GV_BOUNDARY,
  198. line_i, FID, parts);
  199. del_part(parts);
  200. if (build < GV_BUILD_AREAS)
  201. continue;
  202. /* add area (each inner ring is also area) */
  203. dig_line_box(line_i, &box);
  204. dig_find_area_poly(line_i, &area_size);
  205. if (area_size > 0) /* area clockwise */
  206. lines[0] = line;
  207. else
  208. lines[0] = -line;
  209. area = dig_add_area(plus, 1, lines, &box);
  210. /* each area is also isle */
  211. lines[0] = -lines[0]; /* island is counter clockwise */
  212. isle = dig_add_isle(plus, 1, lines, &box);
  213. if (build < GV_BUILD_ATTACH_ISLES)
  214. continue;
  215. if (i == 0) { /* outer ring */
  216. outer_area = area;
  217. }
  218. else { /* inner ring */
  219. struct P_isle *Isle;
  220. Isle = plus->Isle[isle];
  221. Isle->area = outer_area;
  222. dig_area_add_isle(plus, outer_area, isle);
  223. }
  224. }
  225. if (build >= GV_BUILD_CENTROIDS) {
  226. /* create virtual centroid */
  227. ret = Vect_get_point_in_poly_isl((const struct line_pnts *) pg_info->cache.lines[fparts->idx[ipart]],
  228. (const struct line_pnts **) pg_info->cache.lines[fparts->idx[ipart]] + 1,
  229. fparts->nlines[ipart] - 1, &x, &y);
  230. if (ret < -1) {
  231. G_warning(_("Unable to calculate centroid for area %d"),
  232. outer_area);
  233. }
  234. else {
  235. struct P_area *Area;
  236. struct P_topo_c *topo;
  237. struct P_line *Line;
  238. struct line_pnts *line_c;
  239. G_debug(4, " Centroid: %f, %f", x, y);
  240. line_c = Vect_new_line_struct();
  241. Vect_append_point(line_c, x, y, 0.0);
  242. line = add_line(plus, offset, GV_CENTROID, line_c, FID, parts);
  243. Line = plus->Line[line];
  244. topo = (struct P_topo_c *)Line->topo;
  245. topo->area = outer_area;
  246. /* register centroid to area */
  247. Area = plus->Area[outer_area];
  248. Area->centroid = line;
  249. Vect_destroy_line_struct(line_c);
  250. }
  251. }
  252. break;
  253. default:
  254. G_warning(_("Feature type %d not supported"), ftype);
  255. break;
  256. }
  257. return 0;
  258. }
  259. /*!
  260. \brief Build pseudo-topology for PostGIS layers
  261. */
  262. void build_pg(struct Map_info *Map, int build)
  263. {
  264. int iFeature, ipart, fid, nrecords;
  265. char stmt[DB_SQL_MAX];
  266. char *wkb_data;
  267. struct Format_info_pg *pg_info;
  268. struct feat_parts fparts;
  269. struct geom_parts parts;
  270. pg_info = &(Map->fInfo.pg);
  271. /* initialize data structures */
  272. init_parts(&parts);
  273. G_zero(&fparts, sizeof(struct feat_parts));
  274. /* get records */
  275. sprintf(stmt, "SELECT %s,%s FROM %s",
  276. pg_info->fid_column,
  277. pg_info->geom_column, pg_info->table_name);
  278. G_debug(2, "SQL: %s", stmt);
  279. pg_info->res = PQexec(pg_info->conn, stmt);
  280. if (!pg_info->res || PQresultStatus(pg_info->res) != PGRES_TUPLES_OK) {
  281. PQclear(pg_info->res);
  282. G_warning(_("Unable to get features:\n%s"),
  283. PQerrorMessage(pg_info->conn));
  284. return; /* reading failed */
  285. }
  286. /* scan records */
  287. nrecords = PQntuples(pg_info->res);
  288. G_debug(4, "build_pg(): nrecords = %d", nrecords);
  289. for (iFeature = 0; iFeature < nrecords; iFeature++) {
  290. /* get feature id */
  291. fid = atoi(PQgetvalue(pg_info->res, iFeature, 0));
  292. wkb_data = PQgetvalue(pg_info->res, iFeature, 1);
  293. /* cache feature (lines) */
  294. cache_feature(wkb_data,
  295. FALSE, &(pg_info->cache), &fparts);
  296. /* register topo */
  297. reset_parts(&parts);
  298. add_part(&parts, fid);
  299. for (ipart = 0; ipart < fparts.n_parts; ipart++) {
  300. if (fparts.nlines[ipart] < 1) {
  301. G_warning(_("Feature %d without geometry skipped"), fid);
  302. continue;
  303. }
  304. G_debug(4, "Feature: fid = %d part = %d", fid, ipart);
  305. add_part(&parts, ipart);
  306. add_geometry_pg(&(Map->plus), pg_info, &fparts, ipart,
  307. fid, build, &parts);
  308. del_part(&parts);
  309. }
  310. }
  311. Map->plus.built = GV_BUILD_BASE;
  312. PQclear(pg_info->res);
  313. pg_info->res = NULL;
  314. /* free allocated space */
  315. free_parts(&parts);
  316. }
  317. #endif /* HAVE_POSTGRES */
  318. #ifdef HAVE_OGR
  319. /*!
  320. \brief Recursively add geometry (OGR) to topology
  321. */
  322. int add_geometry_ogr(struct Plus_head *plus,
  323. struct Format_info_ogr *ogr_info,
  324. OGRGeometryH hGeom, int FID, int build,
  325. struct geom_parts *parts)
  326. {
  327. int i, ret;
  328. int line;
  329. int area, isle, outer_area;
  330. int lines[1];
  331. double area_size, x, y;
  332. int eType, nRings, iPart, nParts, nPoints;
  333. struct bound_box box;
  334. struct P_line *Line;
  335. struct Format_info_offset *offset;
  336. OGRGeometryH hGeom2, hRing;
  337. G_debug(4, "add_geometry_ogr() FID = %d", FID);
  338. offset = &(ogr_info->offset);
  339. /* allocate space in cache */
  340. if (!ogr_info->cache.lines) {
  341. ogr_info->cache.lines_alloc = 1;
  342. ogr_info->cache.lines = (struct line_pnts **) G_malloc(sizeof(struct line_pnts *));
  343. ogr_info->cache.lines_types = (int *) G_malloc(sizeof(int));
  344. ogr_info->cache.lines[0] = Vect_new_line_struct();
  345. ogr_info->cache.lines_types[0] = -1;
  346. }
  347. outer_area = 0;
  348. eType = wkbFlatten(OGR_G_GetGeometryType(hGeom));
  349. G_debug(4, "OGR type = %d", eType);
  350. switch (eType) {
  351. case wkbPoint:
  352. G_debug(4, "Point");
  353. ogr_info->cache.lines_types[0] = GV_POINT;
  354. Vect_reset_line(ogr_info->cache.lines[0]);
  355. Vect_append_point(ogr_info->cache.lines[0], OGR_G_GetX(hGeom, 0),
  356. OGR_G_GetY(hGeom, 0), OGR_G_GetZ(hGeom, 0));
  357. add_line(plus, offset, GV_POINT, ogr_info->cache.lines[0], FID, parts);
  358. break;
  359. case wkbLineString:
  360. G_debug(4, "LineString");
  361. ogr_info->cache.lines_types[0] = GV_LINE;
  362. nPoints = OGR_G_GetPointCount(hGeom);
  363. Vect_reset_line(ogr_info->cache.lines[0]);
  364. for (i = 0; i < nPoints; i++) {
  365. Vect_append_point(ogr_info->cache.lines[0],
  366. OGR_G_GetX(hGeom, i), OGR_G_GetY(hGeom, i),
  367. OGR_G_GetZ(hGeom, i));
  368. }
  369. add_line(plus, offset, GV_LINE, ogr_info->cache.lines[0], FID, parts);
  370. break;
  371. case wkbPolygon:
  372. G_debug(4, "Polygon");
  373. nRings = OGR_G_GetGeometryCount(hGeom);
  374. G_debug(4, "Number of rings: %d", nRings);
  375. /* alloc space for islands if needed */
  376. if (nRings > ogr_info->cache.lines_alloc) {
  377. ogr_info->cache.lines_alloc += 20;
  378. ogr_info->cache.lines = (struct line_pnts **) G_realloc(ogr_info->cache.lines,
  379. ogr_info->cache.lines_alloc *
  380. sizeof(struct line_pnts *));
  381. ogr_info->cache.lines_types = (int *) G_realloc(ogr_info->cache.lines_types,
  382. ogr_info->cache.lines_alloc * sizeof(int));
  383. for (i = ogr_info->cache.lines_alloc - 20; i < ogr_info->cache.lines_alloc; i++) {
  384. ogr_info->cache.lines[i] = Vect_new_line_struct();
  385. ogr_info->cache.lines_types[i] = -1;
  386. }
  387. }
  388. /* go thru rings */
  389. for (iPart = 0; iPart < nRings; iPart++) {
  390. ogr_info->cache.lines_types[iPart] = GV_BOUNDARY;
  391. hRing = OGR_G_GetGeometryRef(hGeom, iPart);
  392. nPoints = OGR_G_GetPointCount(hRing);
  393. G_debug(4, " ring %d : nPoints = %d", iPart, nPoints);
  394. Vect_reset_line(ogr_info->cache.lines[iPart]);
  395. for (i = 0; i < nPoints; i++) {
  396. Vect_append_point(ogr_info->cache.lines[iPart],
  397. OGR_G_GetX(hRing, i), OGR_G_GetY(hRing, i),
  398. OGR_G_GetZ(hRing, i));
  399. }
  400. /* register boundary */
  401. add_part(parts, iPart);
  402. line = add_line(plus, offset, GV_BOUNDARY, ogr_info->cache.lines[iPart], FID, parts);
  403. del_part(parts);
  404. if (build < GV_BUILD_AREAS)
  405. continue;
  406. /* add area (each inner ring is also area) */
  407. dig_line_box(ogr_info->cache.lines[iPart], &box);
  408. dig_find_area_poly(ogr_info->cache.lines[iPart], &area_size);
  409. if (area_size > 0) /* area clockwise */
  410. lines[0] = line;
  411. else
  412. lines[0] = -line;
  413. area = dig_add_area(plus, 1, lines, &box);
  414. /* each area is also isle */
  415. lines[0] = -lines[0]; /* island is counter clockwise */
  416. isle = dig_add_isle(plus, 1, lines, &box);
  417. if (build < GV_BUILD_ATTACH_ISLES)
  418. continue;
  419. if (iPart == 0) { /* outer ring */
  420. outer_area = area;
  421. }
  422. else { /* inner ring */
  423. struct P_isle *Isle;
  424. Isle = plus->Isle[isle];
  425. Isle->area = outer_area;
  426. dig_area_add_isle(plus, outer_area, isle);
  427. }
  428. }
  429. if (build >= GV_BUILD_CENTROIDS) {
  430. /* create virtual centroid */
  431. ret = Vect_get_point_in_poly_isl((const struct line_pnts *) ogr_info->cache.lines[0],
  432. (const struct line_pnts **) ogr_info->cache.lines + 1,
  433. nRings - 1, &x, &y);
  434. if (ret < -1) {
  435. G_warning(_("Unable to calculate centroid for area %d"),
  436. outer_area);
  437. }
  438. else {
  439. struct P_area *Area;
  440. struct P_topo_c *topo;
  441. G_debug(4, " Centroid: %f, %f", x, y);
  442. Vect_reset_line(ogr_info->cache.lines[0]);
  443. Vect_append_point(ogr_info->cache.lines[0], x, y, 0.0);
  444. line = add_line(plus, offset, GV_CENTROID, ogr_info->cache.lines[0],
  445. FID, parts);
  446. Line = plus->Line[line];
  447. topo = (struct P_topo_c *)Line->topo;
  448. topo->area = outer_area;
  449. /* register centroid to area */
  450. Area = plus->Area[outer_area];
  451. Area->centroid = line;
  452. }
  453. }
  454. break;
  455. case wkbMultiPoint:
  456. case wkbMultiLineString:
  457. case wkbMultiPolygon:
  458. case wkbGeometryCollection:
  459. nParts = OGR_G_GetGeometryCount(hGeom);
  460. G_debug(4, "%d geoms -> next level", nParts);
  461. /* alloc space for parts if needed */
  462. if (nParts > ogr_info->cache.lines_alloc) {
  463. ogr_info->cache.lines_alloc += 20;
  464. ogr_info->cache.lines = (struct line_pnts **) G_realloc(ogr_info->cache.lines,
  465. ogr_info->cache.lines_alloc *
  466. sizeof(struct line_pnts *));
  467. ogr_info->cache.lines_types = (int *) G_realloc(ogr_info->cache.lines_types,
  468. ogr_info->cache.lines_alloc * sizeof(int));
  469. for (i = ogr_info->cache.lines_alloc - 20; i < ogr_info->cache.lines_alloc; i++) {
  470. ogr_info->cache.lines[i] = Vect_new_line_struct();
  471. ogr_info->cache.lines_types[i] = -1;
  472. }
  473. }
  474. /* go thru all parts */
  475. for (i = 0; i < nParts; i++) {
  476. add_part(parts, i);
  477. hGeom2 = OGR_G_GetGeometryRef(hGeom, i);
  478. add_geometry_ogr(plus, ogr_info, hGeom2, FID, build, parts);
  479. del_part(parts);
  480. }
  481. break;
  482. default:
  483. G_warning(_("OGR feature type %d not supported"), eType);
  484. break;
  485. }
  486. return 0;
  487. }
  488. void build_ogr(struct Map_info *Map, int build)
  489. {
  490. int iFeature, FID;
  491. struct Format_info_ogr *ogr_info;
  492. OGRFeatureH hFeature;
  493. OGRGeometryH hGeom;
  494. struct geom_parts parts;
  495. ogr_info = &(Map->fInfo.ogr);
  496. /* initialize data structures */
  497. init_parts(&parts);
  498. /* Note: Do not use OGR_L_GetFeatureCount (it may scan all features) */
  499. OGR_L_ResetReading(ogr_info->layer);
  500. iFeature = 0;
  501. while ((hFeature = OGR_L_GetNextFeature(ogr_info->layer)) != NULL) {
  502. iFeature++;
  503. G_debug(3, " Feature %d", iFeature);
  504. hGeom = OGR_F_GetGeometryRef(hFeature);
  505. if (hGeom == NULL) {
  506. G_warning(_("Feature %d without geometry skipped"), iFeature);
  507. OGR_F_Destroy(hFeature);
  508. continue;
  509. }
  510. FID = (int) OGR_F_GetFID(hFeature);
  511. if (FID == OGRNullFID) {
  512. G_warning(_("OGR feature %d without ID skipped"), iFeature);
  513. OGR_F_Destroy(hFeature);
  514. continue;
  515. }
  516. G_debug(4, " FID = %d", FID);
  517. reset_parts(&parts);
  518. add_part(&parts, FID);
  519. add_geometry_ogr(&(Map->plus), ogr_info, hGeom,
  520. FID, build, &parts);
  521. OGR_F_Destroy(hFeature);
  522. } /* while */
  523. Map->plus.built = GV_BUILD_BASE;
  524. free_parts(&parts);
  525. }
  526. #endif /* HAVE_OGR */
  527. /*!
  528. \brief Build pseudo-topology (for simple features) - internal use only
  529. See Vect_build_ogr() and Vect_build_pg() for implemetation issues.
  530. Build levels:
  531. - GV_BUILD_NONE
  532. - GV_BUILD_BASE
  533. - GV_BUILD_ATTACH_ISLES
  534. - GV_BUILD_CENTROIDS
  535. - GV_BUILD_ALL
  536. \param Map pointer to Map_info structure
  537. \param build build level
  538. \return 1 on success
  539. \return 0 on error
  540. */
  541. int Vect__build_sfa(struct Map_info *Map, int build)
  542. {
  543. int line;
  544. struct Plus_head *plus;
  545. struct P_line *Line;
  546. plus = &(Map->plus);
  547. /* check if upgrade or downgrade */
  548. if (build < plus->built) {
  549. /* lower level request, currently only GV_BUILD_NONE */
  550. if (plus->built >= GV_BUILD_CENTROIDS && build < GV_BUILD_CENTROIDS) {
  551. /* reset info about areas stored for centroids */
  552. for (line = 1; line <= plus->n_lines; line++) {
  553. Line = plus->Line[line];
  554. if (Line && Line->type == GV_CENTROID) {
  555. struct P_topo_c *topo = (struct P_topo_c *)Line->topo;
  556. topo->area = 0;
  557. }
  558. }
  559. dig_free_plus_areas(plus);
  560. dig_spidx_free_areas(plus);
  561. dig_free_plus_isles(plus);
  562. dig_spidx_free_isles(plus);
  563. }
  564. if (plus->built >= GV_BUILD_AREAS && build < GV_BUILD_AREAS) {
  565. /* reset info about areas stored for lines */
  566. for (line = 1; line <= plus->n_lines; line++) {
  567. Line = plus->Line[line];
  568. if (Line && Line->type == GV_BOUNDARY) {
  569. struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
  570. topo->left = 0;
  571. topo->right = 0;
  572. }
  573. }
  574. dig_free_plus_areas(plus);
  575. dig_spidx_free_areas(plus);
  576. dig_free_plus_isles(plus);
  577. dig_spidx_free_isles(plus);
  578. }
  579. if (plus->built >= GV_BUILD_BASE && build < GV_BUILD_BASE) {
  580. dig_free_plus_nodes(plus);
  581. dig_spidx_free_nodes(plus);
  582. dig_free_plus_lines(plus);
  583. dig_spidx_free_lines(plus);
  584. }
  585. }
  586. else {
  587. if (plus->built < GV_BUILD_BASE) {
  588. if (Map->format == GV_FORMAT_OGR ||
  589. Map->format == GV_FORMAT_OGR_DIRECT) {
  590. #ifdef HAVE_OGR
  591. build_ogr(Map, build);
  592. #else
  593. G_fatal_error(_("GRASS is not compiled with OGR support"));
  594. #endif
  595. }
  596. else if (Map->format == GV_FORMAT_POSTGIS) {
  597. #ifdef HAVE_POSTGRES
  598. build_pg(Map, build);
  599. #else
  600. G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
  601. #endif
  602. }
  603. else {
  604. G_fatal_error(_("%s: Native format unsupported"),
  605. "Vect__build_sfa()");
  606. }
  607. }
  608. }
  609. plus->built = build;
  610. return 1;
  611. }