GRASS GIS 8 Programmer's Manual  8.5.0dev(2024)-36359e2344
build_sfa.c
Go to the documentation of this file.
1 /*!
2  \file lib/vector/Vlib/build_sfa.c
3 
4  \brief Vector library - Building pseudo-topology for simple feature access
5 
6  Higher level functions for reading/writing/manipulating vectors.
7 
8  Line offset is
9  - centroids : FID
10  - other types : index of the first record (which is FID) in offset array.
11 
12  (C) 2001-2012 by the GRASS Development Team
13 
14  This program is free software under the GNU General Public License
15  (>=v2). Read the file COPYING that comes with GRASS for details.
16 
17  \author Radim Blazek
18  \author Piero Cavalieri
19  \author Various updates for GRASS 7 by Martin Landa <landa.martin gmail.com>
20  */
21 
22 #include <stdlib.h>
23 
24 #include <grass/gis.h>
25 #include <grass/vector.h>
26 #include <grass/glocale.h>
27 
28 /*!
29  \brief This structure keeps info about geometry parts above current
30  geometry, path to current geometry in the feature. First 'part' number
31  however is feature id */
32 struct geom_parts {
33  int *part;
34  int a_parts;
35  int n_parts;
36 };
37 
38 static void init_parts(struct geom_parts *);
39 static void reset_parts(struct geom_parts *);
40 static void free_parts(struct geom_parts *);
41 static void add_part(struct geom_parts *, int);
42 static void del_part(struct geom_parts *);
43 static void add_parts_to_offset(struct Format_info_offset *,
44  struct geom_parts *);
45 static int add_line(struct Plus_head *, struct Format_info_offset *, int,
46  struct line_pnts *, int, struct geom_parts *);
47 
48 #ifdef HAVE_POSTGRES
49 #include "pg_local_proto.h"
50 
51 static int add_geometry_pg(struct Plus_head *, struct Format_info_pg *,
52  struct feat_parts *, int, int, int,
53  struct geom_parts *);
54 static void build_pg(struct Map_info *, int);
55 #endif
56 
57 #ifdef HAVE_OGR
58 #include <ogr_api.h>
59 
60 static int add_geometry_ogr(struct Plus_head *, struct Format_info_ogr *,
61  OGRGeometryH, int, int, struct geom_parts *);
62 
63 static void build_ogr(struct Map_info *, int);
64 #endif
65 
66 /*!
67  \brief Init parts
68  */
69 void init_parts(struct geom_parts *parts)
70 {
71  G_zero(parts, sizeof(struct geom_parts));
72 }
73 
74 /*!
75  \brief Reset parts
76  */
77 void reset_parts(struct geom_parts *parts)
78 {
79  parts->n_parts = 0;
80 }
81 
82 /*!
83  \brief Free parts
84  */
85 void free_parts(struct geom_parts *parts)
86 {
87  G_free(parts->part);
88  G_zero(parts, sizeof(struct geom_parts));
89 }
90 
91 /*!
92  \brief Add new part number to parts
93  */
94 void add_part(struct geom_parts *parts, int part)
95 {
96  if (parts->a_parts == parts->n_parts) {
97  parts->a_parts += 10;
98  parts->part =
99  (int *)G_realloc((void *)parts->part, parts->a_parts * sizeof(int));
100  }
101  parts->part[parts->n_parts] = part;
102  parts->n_parts++;
103 }
104 
105 /*!
106  \brief Remove last part
107  */
108 void del_part(struct geom_parts *parts)
109 {
110  parts->n_parts--;
111 }
112 
113 /*!
114  \brief Add parts to offset
115  */
116 void add_parts_to_offset(struct Format_info_offset *offset,
117  struct geom_parts *parts)
118 {
119  int i, j;
120 
121  if (offset->array_num + parts->n_parts >= offset->array_alloc) {
122  offset->array_alloc += parts->n_parts + 1000;
123  offset->array =
124  (int *)G_realloc(offset->array, offset->array_alloc * sizeof(int));
125  }
126  j = offset->array_num;
127  for (i = 0; i < parts->n_parts; i++) {
128  G_debug(4, "add offset %d", parts->part[i]);
129  offset->array[j] = parts->part[i];
130  j++;
131  }
132  offset->array_num += parts->n_parts;
133 }
134 
135 /*!
136  \brief Add line to support structures
137  */
138 int add_line(struct Plus_head *plus, struct Format_info_offset *offset,
139  int type, struct line_pnts *Points, int FID,
140  struct geom_parts *parts)
141 {
142  int line;
143  long offset_value;
144  struct bound_box box;
145 
146  if (type != GV_CENTROID) {
147  /* beginning in the offset array */
148  offset_value = offset->array_num;
149  }
150  else {
151  /* TODO : could be used to statore category ? */
152  /* because centroids are read from topology, not from layer */
153  offset_value = FID;
154  }
155 
156  G_debug(4, "Register line: FID = %d offset = %ld", FID, offset_value);
157  dig_line_box(Points, &box);
158  line = dig_add_line(plus, type, Points, &box, offset_value);
159  G_debug(4, "Line registered with line = %d", line);
160 
161  /* Set box */
162  if (line == 1)
163  Vect_box_copy(&(plus->box), &box);
164  else
165  Vect_box_extend(&(plus->box), &box);
166 
167  if (type != GV_BOUNDARY) {
168  dig_cidx_add_cat(plus, 1, (int)FID, line, type);
169  }
170  else {
171  dig_cidx_add_cat(plus, 0, 0, line, type);
172  }
173 
174  /* because centroids are read from topology, not from layer */
175  if (type != GV_CENTROID)
176  add_parts_to_offset(offset, parts);
177 
178  return line;
179 }
180 
181 #ifdef HAVE_POSTGRES
182 /*!
183  \brief Recursively add geometry (PostGIS) to topology
184  */
185 int add_geometry_pg(struct Plus_head *plus, struct Format_info_pg *pg_info,
186  struct feat_parts *fparts, int ipart, int FID, int build,
187  struct geom_parts *parts)
188 {
189  int line, i, idx, area, isle, outer_area, ret;
190  int lines[1];
191  double area_size, x, y;
192  SF_FeatureType ftype;
193  struct bound_box box;
194  struct Format_info_offset *offset;
195  struct line_pnts *line_i;
196 
197  ftype = fparts->ftype[ipart];
198 
199  G_debug(4, "add_geometry_pg() FID = %d ftype = %d", FID, ftype);
200 
201  offset = &(pg_info->offset);
202 
203  outer_area = 0;
204 
205  switch (ftype) {
206  case SF_POINT:
207  G_debug(4, "Point");
208  line_i = pg_info->cache.lines[fparts->idx[ipart]];
209  add_line(plus, offset, GV_POINT, line_i, FID, parts);
210  break;
211  case SF_LINESTRING:
212  G_debug(4, "LineString");
213  line_i = pg_info->cache.lines[fparts->idx[ipart]];
214  add_line(plus, offset, GV_LINE, line_i, FID, parts);
215  break;
216  case SF_POLYGON:
217  G_debug(4, "Polygon");
218 
219  /* register boundaries */
220  idx = fparts->idx[ipart];
221  for (i = 0; i < fparts->nlines[ipart]; i++) {
222  line_i = pg_info->cache.lines[idx++];
223  G_debug(4, "part %d", i);
224  add_part(parts, i);
225  line = add_line(plus, offset, GV_BOUNDARY, line_i, FID, parts);
226  del_part(parts);
227 
228  if (build < GV_BUILD_AREAS)
229  continue;
230 
231  /* add area (each inner ring is also area) */
232  dig_line_box(line_i, &box);
233  dig_find_area_poly(line_i, &area_size);
234 
235  if (area_size > 0) /* area clockwise */
236  lines[0] = line;
237  else
238  lines[0] = -line;
239 
240  area = dig_add_area(plus, 1, lines, &box);
241 
242  /* each area is also isle */
243  lines[0] = -lines[0]; /* island is counter clockwise */
244 
245  isle = dig_add_isle(plus, 1, lines, &box);
246 
247  if (build < GV_BUILD_ATTACH_ISLES)
248  continue;
249 
250  if (i == 0) { /* outer ring */
251  outer_area = area;
252  }
253  else { /* inner ring */
254  struct P_isle *Isle;
255 
256  Isle = plus->Isle[isle];
257  Isle->area = outer_area;
258 
259  dig_area_add_isle(plus, outer_area, isle);
260  }
261  }
262 
263  if (build >= GV_BUILD_CENTROIDS) {
264  /* create virtual centroid */
266  (const struct line_pnts *)
267  pg_info->cache.lines[fparts->idx[ipart]],
268  (const struct line_pnts **)&pg_info->cache
269  .lines[fparts->idx[ipart]] +
270  1,
271  fparts->nlines[ipart] - 1, &x, &y);
272  if (ret < -1) {
273  G_warning(_("Unable to calculate centroid for area %d"),
274  outer_area);
275  }
276  else {
277  struct P_area *Area;
278  struct P_topo_c *topo;
279  struct P_line *Line;
280  struct line_pnts *line_c;
281 
282  G_debug(4, " Centroid: %f, %f", x, y);
283  line_c = Vect_new_line_struct();
284  Vect_append_point(line_c, x, y, 0.0);
285  line = add_line(plus, offset, GV_CENTROID, line_c, FID, parts);
286 
287  Line = plus->Line[line];
288  topo = (struct P_topo_c *)Line->topo;
289  topo->area = outer_area;
290 
291  /* register centroid to area */
292  Area = plus->Area[outer_area];
293  Area->centroid = line;
294  Vect_destroy_line_struct(line_c);
295  }
296  }
297  break;
298  default:
299  G_warning(_("Feature type %d not supported"), ftype);
300  break;
301  }
302 
303  return 0;
304 }
305 
306 /*!
307  \brief Build pseudo-topology for PostGIS layers
308  */
309 void build_pg(struct Map_info *Map, int build)
310 {
311  int iFeature, ipart, fid, nrecords, npoints;
312  char *wkb_data;
313 
314  struct Format_info_pg *pg_info;
315 
316  struct feat_parts fparts;
317  struct geom_parts parts;
318 
319  pg_info = &(Map->fInfo.pg);
320 
321  /* initialize data structures */
322  init_parts(&parts);
323  G_zero(&fparts, sizeof(struct feat_parts));
324 
325  /* get all features */
326  if (Vect__open_cursor_next_line_pg(pg_info, TRUE, Map->plus.built) != 0)
327  return;
328 
329  /* scan records */
330  npoints = 0;
331  nrecords = PQntuples(pg_info->res);
332  G_debug(4, "build_pg(): nrecords = %d", nrecords);
333  G_message(_("Registering primitives..."));
334  for (iFeature = 0; iFeature < nrecords; iFeature++) {
335  /* get feature id */
336  fid = atoi(PQgetvalue(pg_info->res, iFeature, 1));
337  if (fid < 1)
338  continue; /* PostGIS Topology: skip features with negative
339  * fid (isles, universal face, ...) */
340 
341  wkb_data = PQgetvalue(pg_info->res, iFeature, 0);
342 
343  G_progress(iFeature + 1, 1e4);
344 
345  /* cache feature (lines) */
346  if (SF_NONE == Vect__cache_feature_pg(wkb_data, FALSE, FALSE,
347  &(pg_info->cache), &fparts)) {
348  G_warning(_("Feature %d without geometry skipped"), iFeature + 1);
349  continue;
350  }
351 
352  /* register all parts */
353  reset_parts(&parts);
354  add_part(&parts, fid);
355  for (ipart = 0; ipart < fparts.n_parts; ipart++) {
356  if (fparts.nlines[ipart] < 1) {
357  G_warning(_("Feature %d without geometry skipped"), fid);
358  continue;
359  }
360 
361  npoints += pg_info->cache.lines[ipart]->n_points;
362 
363  G_debug(4, "Feature: fid = %d part = %d", fid, ipart);
364 
365  if (fparts.n_parts > 1)
366  add_part(&parts, ipart);
367  add_geometry_pg(&(Map->plus), pg_info, &fparts, ipart, fid, build,
368  &parts);
369  if (fparts.n_parts > 1)
370  del_part(&parts);
371  }
372 
373  /* read next feature from cache */
374  pg_info->cache.lines_next = 0;
375  }
376  G_progress(1, 1);
377 
378  G_message(n_("One primitive registered", "%d primitives registered",
379  Map->plus.n_lines),
380  Map->plus.n_lines);
381  G_message(n_("One vertex registered", "%d vertices registered", npoints),
382  npoints);
383 
384  Map->plus.built = GV_BUILD_BASE;
385 
386  PQclear(pg_info->res);
387  pg_info->res = NULL;
388 
389  /* free allocated space */
390  free_parts(&parts);
391 }
392 #endif /* HAVE_POSTGRES */
393 
394 #ifdef HAVE_OGR
395 /*!
396  \brief Recursively add geometry (OGR) to topology
397  */
398 int add_geometry_ogr(struct Plus_head *plus, struct Format_info_ogr *ogr_info,
399  OGRGeometryH hGeom, int FID, int build,
400  struct geom_parts *parts)
401 {
402  int i, ret, npoints, line;
403  int area, isle, outer_area;
404  int lines[1];
405  double area_size, x, y;
406  int eType, nRings, iPart, nParts, nPoints;
407 
408  struct bound_box box;
409  struct P_line *Line;
410  struct Format_info_offset *offset;
411 
412  OGRGeometryH hGeom2, hRing;
413 
414  G_debug(4, "add_geometry_ogr() FID = %d", FID);
415 
416  offset = &(ogr_info->offset);
417 
418  /* allocate space in cache */
419  if (!ogr_info->cache.lines) {
420  ogr_info->cache.lines_alloc = 1;
421  ogr_info->cache.lines =
422  (struct line_pnts **)G_malloc(sizeof(struct line_pnts *));
423 
424  ogr_info->cache.lines_types = (int *)G_malloc(sizeof(int));
425  ogr_info->cache.lines[0] = Vect_new_line_struct();
426  ogr_info->cache.lines_types[0] = -1;
427  }
428 
429  npoints = outer_area = 0;
430  eType = wkbFlatten(OGR_G_GetGeometryType(hGeom));
431  G_debug(4, "OGR type = %d", eType);
432 
433  switch (eType) {
434  case wkbPoint:
435  G_debug(4, "Point");
436 
437  ogr_info->cache.lines_types[0] = GV_POINT;
438  Vect_reset_line(ogr_info->cache.lines[0]);
439  Vect_append_point(ogr_info->cache.lines[0], OGR_G_GetX(hGeom, 0),
440  OGR_G_GetY(hGeom, 0), OGR_G_GetZ(hGeom, 0));
441  add_line(plus, offset, GV_POINT, ogr_info->cache.lines[0], FID, parts);
442  npoints += ogr_info->cache.lines[0]->n_points;
443  break;
444 
445  case wkbLineString:
446  G_debug(4, "LineString");
447 
448  ogr_info->cache.lines_types[0] = GV_LINE;
449  nPoints = OGR_G_GetPointCount(hGeom);
450  Vect_reset_line(ogr_info->cache.lines[0]);
451  for (i = 0; i < nPoints; i++) {
452  Vect_append_point(ogr_info->cache.lines[0], OGR_G_GetX(hGeom, i),
453  OGR_G_GetY(hGeom, i), OGR_G_GetZ(hGeom, i));
454  }
455  add_line(plus, offset, GV_LINE, ogr_info->cache.lines[0], FID, parts);
456  npoints += ogr_info->cache.lines[0]->n_points;
457  break;
458 
459  case wkbPolygon:
460  G_debug(4, "Polygon");
461 
462  nRings = OGR_G_GetGeometryCount(hGeom);
463  G_debug(4, "Number of rings: %d", nRings);
464 
465  /* alloc space for islands if needed */
466  if (nRings > ogr_info->cache.lines_alloc) {
467  ogr_info->cache.lines_alloc += nRings;
468  ogr_info->cache.lines = (struct line_pnts **)G_realloc(
469  ogr_info->cache.lines,
470  ogr_info->cache.lines_alloc * sizeof(struct line_pnts *));
471  ogr_info->cache.lines_types =
472  (int *)G_realloc(ogr_info->cache.lines_types,
473  ogr_info->cache.lines_alloc * sizeof(int));
474 
475  for (i = ogr_info->cache.lines_alloc - nRings;
476  i < ogr_info->cache.lines_alloc; i++) {
477  ogr_info->cache.lines[i] = Vect_new_line_struct();
478  ogr_info->cache.lines_types[i] = -1;
479  }
480  }
481 
482  /* go through rings */
483  for (iPart = 0; iPart < nRings; iPart++) {
484  ogr_info->cache.lines_types[iPart] = GV_BOUNDARY;
485  hRing = OGR_G_GetGeometryRef(hGeom, iPart);
486  nPoints = OGR_G_GetPointCount(hRing);
487  G_debug(4, " ring %d : nPoints = %d", iPart, nPoints);
488 
489  Vect_reset_line(ogr_info->cache.lines[iPart]);
490  for (i = 0; i < nPoints; i++) {
491  Vect_append_point(ogr_info->cache.lines[iPart],
492  OGR_G_GetX(hRing, i), OGR_G_GetY(hRing, i),
493  OGR_G_GetZ(hRing, i));
494  }
495  npoints += ogr_info->cache.lines[iPart]->n_points;
496 
497  /* register boundary */
498  add_part(parts, iPart);
499  line = add_line(plus, offset, GV_BOUNDARY,
500  ogr_info->cache.lines[iPart], FID, parts);
501  del_part(parts);
502 
503  if (build < GV_BUILD_AREAS)
504  continue;
505 
506  /* add area (each inner ring is also area) */
507  dig_line_box(ogr_info->cache.lines[iPart], &box);
508  dig_find_area_poly(ogr_info->cache.lines[iPart], &area_size);
509 
510  if (area_size > 0) /* area clockwise */
511  lines[0] = line;
512  else
513  lines[0] = -line;
514 
515  area = dig_add_area(plus, 1, lines, &box);
516 
517  /* each area is also isle */
518  lines[0] = -lines[0]; /* island is counter clockwise */
519 
520  isle = dig_add_isle(plus, 1, lines, &box);
521 
522  if (build < GV_BUILD_ATTACH_ISLES)
523  continue;
524 
525  if (iPart == 0) { /* outer ring */
526  outer_area = area;
527  }
528  else { /* inner ring */
529  struct P_isle *Isle;
530 
531  Isle = plus->Isle[isle];
532  Isle->area = outer_area;
533 
534  dig_area_add_isle(plus, outer_area, isle);
535  }
536  }
537 
538  if (build >= GV_BUILD_CENTROIDS) {
539  /* create virtual centroid */
541  (const struct line_pnts *)ogr_info->cache.lines[0],
542  (const struct line_pnts **)ogr_info->cache.lines + 1,
543  nRings - 1, &x, &y);
544  if (ret < -1) {
545  G_warning(_("Unable to calculate centroid for area %d"),
546  outer_area);
547  }
548  else {
549  struct P_area *Area;
550  struct P_topo_c *topo;
551 
552  G_debug(4, " Centroid: %f, %f", x, y);
553  Vect_reset_line(ogr_info->cache.lines[0]);
554  Vect_append_point(ogr_info->cache.lines[0], x, y, 0.0);
555  line = add_line(plus, offset, GV_CENTROID,
556  ogr_info->cache.lines[0], FID, parts);
557 
558  Line = plus->Line[line];
559  topo = (struct P_topo_c *)Line->topo;
560  topo->area = outer_area;
561 
562  /* register centroid to area */
563  Area = plus->Area[outer_area];
564  Area->centroid = line;
565  }
566  }
567  break;
568 
569  case wkbMultiPoint:
570  case wkbMultiLineString:
571  case wkbMultiPolygon:
572  case wkbGeometryCollection:
573  nParts = OGR_G_GetGeometryCount(hGeom);
574  G_debug(4, "%d geoms -> next level", nParts);
575 
576  /* alloc space for parts if needed */
577  if (nParts > ogr_info->cache.lines_alloc) {
578  ogr_info->cache.lines_alloc += nParts;
579  ogr_info->cache.lines = (struct line_pnts **)G_realloc(
580  ogr_info->cache.lines,
581  ogr_info->cache.lines_alloc * sizeof(struct line_pnts *));
582  ogr_info->cache.lines_types =
583  (int *)G_realloc(ogr_info->cache.lines_types,
584  ogr_info->cache.lines_alloc * sizeof(int));
585 
586  for (i = ogr_info->cache.lines_alloc - nParts;
587  i < ogr_info->cache.lines_alloc; i++) {
588  ogr_info->cache.lines[i] = Vect_new_line_struct();
589  ogr_info->cache.lines_types[i] = -1;
590  }
591  }
592 
593  /* go through all parts */
594  for (i = 0; i < nParts; i++) {
595  add_part(parts, i);
596  hGeom2 = OGR_G_GetGeometryRef(hGeom, i);
597  npoints +=
598  add_geometry_ogr(plus, ogr_info, hGeom2, FID, build, parts);
599  del_part(parts);
600  }
601  break;
602 
603  default:
604  G_warning(_("OGR feature type %d not supported"), eType);
605  break;
606  }
607 
608  return npoints;
609 }
610 
611 void build_ogr(struct Map_info *Map, int build)
612 {
613  int iFeature, FID, npoints, nskipped;
614 
615  struct Format_info_ogr *ogr_info;
616 
617  OGRFeatureH hFeature;
618  OGRGeometryH hGeom;
619 
620  struct geom_parts parts;
621 
622  ogr_info = &(Map->fInfo.ogr);
623 
624  /* initialize data structures */
625  init_parts(&parts);
626 
627  /* Note: Do not use OGR_L_GetFeatureCount (it may scan all features) */
628  OGR_L_ResetReading(ogr_info->layer);
629  if (ogr_info->where)
630  /* set attribute filter if where sql statement defined */
631  OGR_L_SetAttributeFilter(ogr_info->layer, ogr_info->where);
632  npoints = iFeature = nskipped = 0;
633  G_message(_("Registering primitives..."));
634  while ((hFeature = OGR_L_GetNextFeature(ogr_info->layer)) != NULL) {
635  G_debug(3, " Feature %d", iFeature);
636 
637  G_progress(++iFeature, 1e4);
638 
639  hGeom = OGR_F_GetGeometryRef(hFeature);
640  if (hGeom == NULL) {
641  G_debug(3, "Feature %d without geometry skipped", iFeature);
642  OGR_F_Destroy(hFeature);
643  nskipped++;
644  continue;
645  }
646 
647  FID = (int)OGR_F_GetFID(hFeature);
648  if (FID == OGRNullFID) {
649  G_debug(3, "OGR feature %d without ID skipped", iFeature);
650  OGR_F_Destroy(hFeature);
651  nskipped++;
652  continue;
653  }
654  G_debug(4, " FID = %d", FID);
655 
656  reset_parts(&parts);
657  add_part(&parts, FID);
658  npoints +=
659  add_geometry_ogr(&(Map->plus), ogr_info, hGeom, FID, build, &parts);
660 
661  OGR_F_Destroy(hFeature);
662  } /* while */
663  G_progress(1, 1);
664 
665  G_message(n_("One primitive registered", "%d primitives registered",
666  Map->plus.n_lines),
667  Map->plus.n_lines);
668  G_message(n_("One vertex registered", "%d vertices registered", npoints),
669  npoints);
670 
671  if (nskipped > 0)
672  G_warning(n_("One feature without geometry skipped",
673  "%d features without geometry skipped", nskipped),
674  nskipped);
675 
676  Map->plus.built = GV_BUILD_BASE;
677 
678  free_parts(&parts);
679 }
680 #endif /* HAVE_OGR */
681 
682 /*!
683  \brief Build pseudo-topology (for simple features) - internal use only
684 
685  See Vect_build_ogr() and Vect_build_pg() for implementation issues.
686 
687  Build levels:
688  - GV_BUILD_NONE
689  - GV_BUILD_BASE
690  - GV_BUILD_ATTACH_ISLES
691  - GV_BUILD_CENTROIDS
692  - GV_BUILD_ALL
693 
694  \param Map pointer to Map_info structure
695  \param build build level
696 
697  \return 1 on success
698  \return 0 on error
699  */
700 int Vect__build_sfa(struct Map_info *Map, int build)
701 {
702  struct Plus_head *plus;
703 
704  plus = &(Map->plus);
705 
706  /* check if upgrade or downgrade */
707  if (build < plus->built) {
708  /* -> downgrade */
709  Vect__build_downgrade(Map, build);
710  return 1;
711  }
712 
713  /* -> upgrade */
714  if (plus->built < GV_BUILD_BASE) {
715  if (Map->format == GV_FORMAT_OGR ||
716  Map->format == GV_FORMAT_OGR_DIRECT) {
717 #ifdef HAVE_OGR
718  build_ogr(Map, build);
719 #else
720  G_fatal_error(_("GRASS is not compiled with OGR support"));
721 #endif
722  }
723  else if (Map->format == GV_FORMAT_POSTGIS) {
724 #ifdef HAVE_POSTGRES
725  build_pg(Map, build);
726 #else
727  G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
728 #endif
729  }
730  else {
731  G_fatal_error(_("%s: Native format unsupported"),
732  "Vect__build_sfa()");
733  }
734  }
735 
736  plus->built = build;
737 
738  return 1;
739 }
740 
741 /*!
742  \brief Dump feature index to file
743 
744  \param Map pointer to Map_info struct
745  \param out file for output (stdout/stderr for example)
746 
747  \return 1 on success
748  \return 0 on error
749  */
750 int Vect_fidx_dump(struct Map_info *Map, FILE *out)
751 {
752  int i;
753  const struct Format_info_offset *offset;
754 
755  if (Map->format != GV_FORMAT_OGR && Map->format != GV_FORMAT_POSTGIS) {
756  G_warning(_("Feature index is built only for non-native formats. "
757  "Nothing to dump."));
758  return 0;
759  }
760 
761  if (Map->format == GV_FORMAT_OGR)
762  offset = &(Map->fInfo.ogr.offset);
763  else
764  offset = &(Map->fInfo.pg.offset);
765 
766  fprintf(out, "---------- FEATURE INDEX DUMP ----------\n");
767 
768  fprintf(out, "format: %s\n", Vect_maptype_info(Map));
770  fprintf(out, "topology: PostGIS\n");
771  else
772  fprintf(out, "topology: pseudo\n");
773  fprintf(out, "feature type: %s\n", Vect_get_finfo_geometry_type(Map));
774  fprintf(out,
775  "number of features: %d\n\noffset : value (fid or part idx):\n",
776  Vect_get_num_lines(Map));
777  for (i = 0; i < offset->array_num; i++) {
778  fprintf(out, "%6d : %d\n", i, offset->array[i]);
779  }
780 
781  return 1;
782 }
int Vect__build_sfa(struct Map_info *Map, int build)
Build pseudo-topology (for simple features) - internal use only.
Definition: build_sfa.c:700
int Vect_fidx_dump(struct Map_info *Map, FILE *out)
Dump feature index to file.
Definition: build_sfa.c:750
#define NULL
Definition: ccmath.h:32
void G_zero(void *, int)
Zero out a buffer, buf, of length i.
Definition: gis/zero.c:23
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#define G_realloc(p, n)
Definition: defs/gis.h:96
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
void G_progress(long, int)
Print progress info messages.
Definition: percent.c:158
#define G_malloc(n)
Definition: defs/gis.h:94
void G_message(const char *,...) __attribute__((format(printf
int G_debug(int, const char *,...) __attribute__((format(printf
void Vect_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
Definition: line.c:77
plus_t Vect_get_num_lines(struct Map_info *)
Fetch number of features (points, lines, boundaries, centroids) in vector map.
Definition: level_two.c:75
int Vect_get_point_in_poly_isl(const struct line_pnts *, const struct line_pnts **, int, double *, double *)
Get point inside polygon but outside the islands specifiled in IPoints.
Definition: Vlib/poly.c:449
void Vect__build_downgrade(struct Map_info *, int)
Downgrade build level (for internal use only)
Definition: build.c:771
int Vect_box_extend(struct bound_box *, const struct bound_box *)
Extend box A by box B.
int Vect_maptype(struct Map_info *)
Gets vector map format.
const char * Vect_maptype_info(struct Map_info *)
Gets vector map format (as string)
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition: line.c:45
const char * Vect_get_finfo_geometry_type(struct Map_info *)
Get geometry type as string (relevant only for non-native formats)
Definition: header_finfo.c:143
void Vect_reset_line(struct line_pnts *)
Reset line.
Definition: line.c:129
int Vect_append_point(struct line_pnts *, double, double, double)
Appends one point to the end of a line.
Definition: line.c:148
int Vect_box_copy(struct bound_box *, const struct bound_box *)
Copy box B to box A.
#define GV_CENTROID
Definition: dig_defines.h:186
SF_FeatureType
Simple feature types.
Definition: dig_defines.h:239
@ SF_POLYGON
Definition: dig_defines.h:244
@ SF_NONE
Definition: dig_defines.h:252
@ SF_LINESTRING
Definition: dig_defines.h:242
@ SF_POINT
Definition: dig_defines.h:241
#define GV_FORMAT_POSTGIS
PostGIS format.
Definition: dig_defines.h:89
#define GV_LINE
Definition: dig_defines.h:184
#define GV_POINT
Feature types used in memory on run time (may change)
Definition: dig_defines.h:183
#define GV_BOUNDARY
Definition: dig_defines.h:185
#define GV_BUILD_ATTACH_ISLES
Topology levels - attach islands to areas.
Definition: dig_defines.h:129
#define GV_BUILD_BASE
Topology levels - basic level (without areas and isles)
Definition: dig_defines.h:125
#define GV_BUILD_AREAS
Topology levels - build areas.
Definition: dig_defines.h:127
#define GV_BUILD_CENTROIDS
Topology levels - assign centroids to areas.
Definition: dig_defines.h:131
#define GV_FORMAT_OGR_DIRECT
OGR format (direct access)
Definition: dig_defines.h:87
#define GV_FORMAT_OGR
OGR format.
Definition: dig_defines.h:85
int dig_add_isle(struct Plus_head *, int, plus_t *, struct bound_box *)
Allocate space for new island and create boundary info from array.
Definition: plus_area.c:703
int dig_area_add_isle(struct Plus_head *, int, int)
Add isle to area if does not exist yet.
Definition: plus_area.c:265
int dig_cidx_add_cat(struct Plus_head *, int, int, int, int)
Definition: diglib/cindex.c:72
int dig_add_area(struct Plus_head *, int, plus_t *, struct bound_box *)
Allocate space for new area and create boundary info from array.
Definition: plus_area.c:187
int dig_find_area_poly(struct line_pnts *, double *)
Definition: diglib/poly.c:98
int dig_add_line(struct Plus_head *, int, const struct line_pnts *, const struct bound_box *, off_t)
Add new line to Plus_head structure.
Definition: plus_line.c:133
int dig_line_box(const struct line_pnts *, struct bound_box *)
#define TRUE
Definition: gis.h:79
#define FALSE
Definition: gis.h:83
#define n_(strs, strp, num)
Definition: glocale.h:11
#define _(str)
Definition: glocale.h:10
SF_FeatureType Vect__cache_feature_pg(const char *data, int skip_polygon, int force_type, struct Format_info_cache *cache, struct feat_parts *fparts)
Read geometry from HEX data.
Definition: read_pg.c:778
int Vect__open_cursor_next_line_pg(struct Format_info_pg *pg_info, int fetch_all, int built_level)
Create select cursor for sequential access (internal use only)
Definition: read_pg.c:1252
int lines_next
Next line to be read from cache.
Definition: dig_structs.h:482
int * lines_types
List of line types (GV_POINT, GV_LINE, ...)
Definition: dig_structs.h:466
struct line_pnts ** lines
Lines array.
Definition: dig_structs.h:462
int lines_alloc
Number of allocated lines in cache.
Definition: dig_structs.h:474
Data structure used for building pseudo-topology.
Definition: dig_structs.h:388
int * array
Offset list.
Definition: dig_structs.h:436
int array_alloc
Space allocated for offset list.
Definition: dig_structs.h:444
int array_num
Number of items in offset list.
Definition: dig_structs.h:440
Non-native format info (OGR)
Definition: dig_structs.h:505
char * where
SQL where statement (to filter features)
Definition: dig_structs.h:521
OGRLayerH layer
Pointer to OGRLayer.
Definition: dig_structs.h:534
struct Format_info_offset offset
Offset list used for building pseudo-topology.
Definition: dig_structs.h:577
struct Format_info_cache cache
Lines cache for reading feature.
Definition: dig_structs.h:561
Non-native format info (PostGIS)
Definition: dig_structs.h:590
char * toposchema_name
Topology schema name and id.
Definition: dig_structs.h:686
PGresult * res
Definition: dig_structs.h:651
struct Format_info_cache cache
Lines cache for reading feature.
Definition: dig_structs.h:670
struct Format_info_offset offset
Offset list used for building pseudo-topology (simple features access)
Definition: dig_structs.h:676
struct Format_info_pg pg
PostGIS info.
Definition: dig_structs.h:712
struct Format_info_ogr ogr
OGR info.
Definition: dig_structs.h:708
Vector map info.
Definition: dig_structs.h:1243
int format
Map format (native, ogr, postgis)
Definition: dig_structs.h:1255
struct Format_info fInfo
Format info for non-native formats.
Definition: dig_structs.h:1400
struct Plus_head plus
Plus info (topology, version, ...)
Definition: dig_structs.h:1270
Area (topology) info.
Definition: dig_structs.h:1583
plus_t centroid
Number of first centroid within area.
Definition: dig_structs.h:1605
Isle (topology) info.
Definition: dig_structs.h:1623
plus_t area
Area it exists w/in, if any.
Definition: dig_structs.h:1645
Vector geometry.
Definition: dig_structs.h:1553
void * topo
Topology info.
Definition: dig_structs.h:1577
Centroid topology.
Definition: dig_structs.h:1514
plus_t area
Area number, negative for duplicate centroid.
Definition: dig_structs.h:1518
Basic topology-related info.
Definition: dig_structs.h:769
struct P_line ** Line
Array of vector geometries.
Definition: dig_structs.h:871
plus_t n_lines
Current number of lines.
Definition: dig_structs.h:931
struct P_area ** Area
Array of areas.
Definition: dig_structs.h:875
struct bound_box box
Bounding box of features.
Definition: dig_structs.h:861
struct P_isle ** Isle
Array of isles.
Definition: dig_structs.h:879
int built
Highest level of topology currently available.
Definition: dig_structs.h:857
Bounding box.
Definition: dig_structs.h:64
Feature geometry info - coordinates.
Definition: dig_structs.h:1651
double * y
Array of Y coordinates.
Definition: dig_structs.h:1659
int n_points
Number of points.
Definition: dig_structs.h:1667
void add_part(SYMBOL *s, SYMBPART *p)
Definition: symbol/read.c:71
#define x