GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
build_ogr.c
Go to the documentation of this file.
1 
20 #include <string.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <grass/gis.h>
24 #include <grass/Vect.h>
25 #include <grass/glocale.h>
26 
27 /*
28  * Line offset is
29  * - centroids : FID
30  * - other types : index of the first record (which is FID) in offset array.
31  *
32  * Category: FID, not all layer have FID, OGRNullFID is defined (5/2004) as -1, so FID should be only >= 0
33  *
34  */
35 
36 #ifdef HAVE_OGR
37 #include <ogr_api.h>
38 
39 /*
40  * This structure keeps info about geometry parts above current geometry, path to curent geometry in the
41  * feature. First 'part' number however is feature Id
42  */
43 typedef struct
44 {
45  int *part;
46  int a_parts;
47  int n_parts;
48 } GEOM_PARTS;
49 
50 /* Init parts */
51 static void init_parts(GEOM_PARTS * parts)
52 {
53  parts->part = NULL;
54  parts->a_parts = parts->n_parts = 0;
55 }
56 
57 /* Reset parts */
58 static void reset_parts(GEOM_PARTS * parts)
59 {
60  parts->n_parts = 0;
61 }
62 
63 /* Free parts */
64 static void free_parts(GEOM_PARTS * parts)
65 {
66  free(parts->part);
67  parts->a_parts = parts->n_parts = 0;
68 }
69 
70 /* Add new part number to parts */
71 static void add_part(GEOM_PARTS * parts, int part)
72 {
73  if (parts->a_parts == parts->n_parts) {
74  parts->a_parts += 10;
75  parts->part =
76  (int *)G_realloc((void *)parts->part,
77  parts->a_parts * sizeof(int));
78  }
79  parts->part[parts->n_parts] = part;
80  parts->n_parts++;
81 }
82 
83 /* Remove last part */
84 static void del_part(GEOM_PARTS * parts)
85 {
86  parts->n_parts--;
87 }
88 
89 /* Add parts to offset */
90 static void add_parts_to_offset(struct Map_info *Map, GEOM_PARTS * parts)
91 {
92  int i, j;
93 
94  if (Map->fInfo.ogr.offset_num + parts->n_parts >=
95  Map->fInfo.ogr.offset_alloc) {
96  Map->fInfo.ogr.offset_alloc += parts->n_parts + 1000;
97  Map->fInfo.ogr.offset = (int *)G_realloc(Map->fInfo.ogr.offset,
98  Map->fInfo.ogr.offset_alloc *
99  sizeof(int));
100  }
101  j = Map->fInfo.ogr.offset_num;
102  for (i = 0; i < parts->n_parts; i++) {
103  G_debug(4, "add offset %d", parts->part[i]);
104  Map->fInfo.ogr.offset[j] = parts->part[i];
105  j++;
106  }
107  Map->fInfo.ogr.offset_num += parts->n_parts;
108 }
109 
110 /* add line to support structures */
111 static int add_line(struct Map_info *Map, int type, struct line_pnts *Points,
112  int FID, GEOM_PARTS * parts)
113 {
114  int line;
115  struct Plus_head *plus;
116  long offset;
117  BOUND_BOX box;
118 
119  plus = &(Map->plus);
120 
121  if (type != GV_CENTROID) {
122  offset = Map->fInfo.ogr.offset_num; /* beginning in the offset array */
123  }
124  else {
125  /* TODO : could be used to statore category ? */
126  offset = FID; /* because centroids are read from topology, not from layer */
127  }
128  G_debug(4, "Register line: FID = %d offset = %ld", FID, offset);
129  line = dig_add_line(plus, type, Points, offset);
130  G_debug(4, "Line registered with line = %d", line);
131 
132  /* Set box */
133  dig_line_box(Points, &box);
134  if (line == 1)
135  Vect_box_copy(&(plus->box), &box);
136  else
137  Vect_box_extend(&(plus->box), &box);
138 
139  if (type != GV_BOUNDARY) {
140  dig_cidx_add_cat(plus, 1, (int)FID, line, type);
141  }
142  else {
143  dig_cidx_add_cat(plus, 0, 0, line, type);
144  }
145 
146  if (type != GV_CENTROID) /* because centroids are read from topology, not from layer */
147  add_parts_to_offset(Map, parts);
148 
149  return line;
150 }
151 
152 /* Recursively add geometry to topology */
153 static int add_geometry(struct Map_info *Map, OGRGeometryH hGeom, int FID,
154  GEOM_PARTS * parts)
155 {
156  struct Plus_head *plus;
157  int i, ret;
158  int line;
159  int area, isle, outer_area = 0;
160  int lines[1];
161  static struct line_pnts **Points = NULL;
162  static int alloc_points = 0;
163  BOUND_BOX box;
164  P_LINE *Line;
165  double area_size, x, y;
166  int eType, nRings, iPart, nParts, nPoints;
167  OGRGeometryH hGeom2, hRing;
168 
169  G_debug(4, "add_geometry() FID = %d", FID);
170  plus = &(Map->plus);
171 
172  if (!Points) {
173  alloc_points = 1;
174  Points = (struct line_pnts **)G_malloc(sizeof(struct line_pnts *));
175  Points[0] = Vect_new_line_struct();
176  }
177  Vect_reset_line(Points[0]);
178 
179  eType = wkbFlatten(OGR_G_GetGeometryType(hGeom));
180  G_debug(4, "OGR type = %d", eType);
181 
182  switch (eType) {
183  case wkbPoint:
184  G_debug(4, "Point");
185  Vect_append_point(Points[0], OGR_G_GetX(hGeom, 0),
186  OGR_G_GetY(hGeom, 0), OGR_G_GetZ(hGeom, 0));
187  add_line(Map, GV_POINT, Points[0], FID, parts);
188  break;
189 
190  case wkbLineString:
191  G_debug(4, "LineString");
192  nPoints = OGR_G_GetPointCount(hGeom);
193  for (i = 0; i < nPoints; i++) {
194  Vect_append_point(Points[0],
195  OGR_G_GetX(hGeom, i), OGR_G_GetY(hGeom, i),
196  OGR_G_GetZ(hGeom, i));
197  }
198  add_line(Map, GV_LINE, Points[0], FID, parts);
199  break;
200 
201  case wkbPolygon:
202  G_debug(4, "Polygon");
203 
204  nRings = OGR_G_GetGeometryCount(hGeom);
205  G_debug(4, "Number of rings: %d", nRings);
206 
207  /* Alloc space for islands */
208  if (nRings >= alloc_points) {
209  Points = (struct line_pnts **)G_realloc((void *)Points,
210  nRings *
211  sizeof(struct line_pnts
212  *));
213  for (i = alloc_points; i < nRings; i++) {
214  Points[i] = Vect_new_line_struct();
215  }
216  }
217 
218  for (iPart = 0; iPart < nRings; iPart++) {
219  hRing = OGR_G_GetGeometryRef(hGeom, iPart);
220  nPoints = OGR_G_GetPointCount(hRing);
221  G_debug(4, " ring %d : nPoints = %d", iPart, nPoints);
222 
223 
224  Vect_reset_line(Points[iPart]);
225  for (i = 0; i < nPoints; i++) {
226  Vect_append_point(Points[iPart],
227  OGR_G_GetX(hRing, i), OGR_G_GetY(hRing, i),
228  OGR_G_GetZ(hRing, i));
229  }
230 
231  /* register line */
232  add_part(parts, iPart);
233  line = add_line(Map, GV_BOUNDARY, Points[iPart], FID, parts);
234  del_part(parts);
235 
236  /* add area (each inner ring is also area) */
237  dig_line_box(Points[iPart], &box);
238  dig_find_area_poly(Points[iPart], &area_size);
239 
240  if (area_size > 0) /* clockwise */
241  lines[0] = line;
242  else
243  lines[0] = -line;
244 
245  area = dig_add_area(plus, 1, lines);
246  dig_area_set_box(plus, area, &box);
247 
248  /* Each area is also isle */
249  lines[0] = -lines[0]; /* island is counter clockwise */
250 
251  isle = dig_add_isle(plus, 1, lines);
252  dig_isle_set_box(plus, isle, &box);
253 
254  if (iPart == 0) { /* outer ring */
255  outer_area = area;
256  }
257  else { /* inner ring */
258  P_ISLE *Isle;
259 
260  Isle = plus->Isle[isle];
261  Isle->area = outer_area;
262 
263  dig_area_add_isle(plus, outer_area, isle);
264  }
265  }
266 
267  /* create virtual centroid */
268  ret =
269  Vect_get_point_in_poly_isl(Points[0], Points + 1, nRings - 1, &x,
270  &y);
271  if (ret < -1) {
272  G_warning(_("Unable to calculate centroid for area %d"),
273  outer_area);
274  }
275  else {
276  P_AREA *Area;
277 
278  G_debug(4, " Centroid: %f, %f", x, y);
279  Vect_reset_line(Points[0]);
280  Vect_append_point(Points[0], x, y, 0.0);
281  line = add_line(Map, GV_CENTROID, Points[0], FID, parts);
282  dig_line_box(Points[0], &box);
283  dig_line_set_box(plus, line, &box);
284 
285  Line = plus->Line[line];
286  Line->left = outer_area;
287 
288  /* register centroid to area */
289  Area = plus->Area[outer_area];
290  Area->centroid = line;
291  }
292  break;
293 
294  case wkbMultiPoint:
295  case wkbMultiLineString:
296  case wkbMultiPolygon:
297  case wkbGeometryCollection:
298  nParts = OGR_G_GetGeometryCount(hGeom);
299  G_debug(4, "%d geoms -> next level", nParts);
300  for (i = 0; i < nParts; i++) {
301  add_part(parts, i);
302  hGeom2 = OGR_G_GetGeometryRef(hGeom, i);
303  add_geometry(Map, hGeom2, FID, parts);
304  del_part(parts);
305  }
306  break;
307 
308  default:
309  G_warning(_("OGR feature type %d not supported"), eType);
310  break;
311  }
312 
313  return 0;
314 }
315 
325 int Vect_build_ogr(struct Map_info *Map, int build)
326 {
327  int iFeature, count, FID;
328  GEOM_PARTS parts;
329  OGRFeatureH hFeature;
330  OGRGeometryH hGeom;
331 
332  if (build != GV_BUILD_ALL)
333  G_fatal_error(_("Partial build for OGR is not supported"));
334 
335  /* TODO move this init to better place (Vect_open_ ?), because in theory build may be reused on level2 */
336  Map->fInfo.ogr.offset = NULL;
337  Map->fInfo.ogr.offset_num = 0;
338  Map->fInfo.ogr.offset_alloc = 0;
339 
340  /* test layer capabilities */
341  if (!OGR_L_TestCapability(Map->fInfo.ogr.layer, OLCRandomRead)) {
342  G_warning(_("Random read is not supported by OGR for this layer, cannot build support"));
343  return 0;
344  }
345 
346  init_parts(&parts);
347 
348  /* Note: Do not use OGR_L_GetFeatureCount (it may scan all features)!!! */
349  G_verbose_message(_("Feature: "));
350 
351  OGR_L_ResetReading(Map->fInfo.ogr.layer);
352  count = iFeature = 0;
353  while ((hFeature = OGR_L_GetNextFeature(Map->fInfo.ogr.layer)) != NULL) {
354  iFeature++;
355  count++;
356 
357  G_debug(4, "---- Feature %d ----", iFeature);
358 
359  hGeom = OGR_F_GetGeometryRef(hFeature);
360  if (hGeom == NULL) {
361  G_warning(_("Feature %d without geometry ignored"), iFeature);
362  OGR_F_Destroy(hFeature);
363  continue;
364  }
365 
366  FID = (int)OGR_F_GetFID(hFeature);
367  if (FID == OGRNullFID) {
368  G_warning(_("OGR feature without ID ignored"));
369  OGR_F_Destroy(hFeature);
370  continue;
371  }
372  G_debug(3, "FID = %d", FID);
373 
374  reset_parts(&parts);
375  add_part(&parts, FID);
376  add_geometry(Map, hGeom, FID, &parts);
377 
378  OGR_F_Destroy(hFeature);
379  } /* while */
380  free_parts(&parts);
381 
382  Map->plus.built = GV_BUILD_ALL;
383  return 1;
384 }
385 #endif
int * part
Definition: build_ogr.c:45
int dig_line_box(struct line_pnts *Points, BOUND_BOX *Box)
Definition: diglib/box.c:24
struct line_pnts * Vect_new_line_struct()
Creates and initializes a struct line_pnts.
Definition: line.c:57
int dig_add_line(struct Plus_head *plus, int type, struct line_pnts *Points, long offset)
Add new line to Plus_head structure.
Definition: plus_line.c:102
int Vect_build_ogr(struct Map_info *Map, int build)
Build topology.
Definition: build_ogr.c:325
int count
int Vect_reset_line(struct line_pnts *Points)
Reset line.
Definition: line.c:148
int y
Definition: plot.c:34
tuple box
surface = wx.CheckBox(parent = panel, id = wx.ID_ANY, label = _(&quot;Follow source viewpoint&quot;)) pageSizer...
Definition: tools.py:1527
int Vect_append_point(struct line_pnts *Points, double x, double y, double z)
Appends one point to the end of a line.
Definition: line.c:168
int Vect_box_extend(BOUND_BOX *A, BOUND_BOX *B)
Extend box A by box B.
Definition: Vlib/box.c:93
int dig_area_add_isle(struct Plus_head *plus, int area, int isle)
Add isle to area if does not exist yet.
Definition: plus_area.c:253
void G_verbose_message(const char *msg,...)
Print a message to stderr but only if module is in verbose mode.
Definition: lib/gis/error.c:95
int dig_cidx_add_cat(struct Plus_head *Plus, int field, int cat, int line, int type)
Definition: diglib/cindex.c:68
int Vect_get_point_in_poly_isl(struct line_pnts *Points, struct line_pnts **IPoints, int n_isles, double *att_x, double *att_y)
Get point inside polygon but outside the islands specifiled in IPoints.
Definition: Vlib/poly.c:424
int dig_isle_set_box(struct Plus_head *plus, plus_t isle, BOUND_BOX *Box)
Set isle bounding box.
Definition: plus_area.c:720
int Vect_box_copy(BOUND_BOX *A, BOUND_BOX *B)
Copy box B to box A.
Definition: Vlib/box.c:72
int
Definition: g3dcolor.c:48
int a_parts
Definition: build_ogr.c:46
return NULL
Definition: dbfopen.c:1394
int n_parts
Definition: build_ogr.c:47
G_warning("category support for [%s] in mapset [%s] %s", name, mapset, type)
tuple Map
Definition: render.py:1310
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: gis/debug.c:51
int dig_find_area_poly(struct line_pnts *Points, double *totalarea)
Definition: diglib/poly.c:93
void free(void *)
int dig_area_set_box(struct Plus_head *plus, plus_t area, BOUND_BOX *Box)
Set area bounding box.
Definition: plus_area.c:441
int G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
int dig_add_isle(struct Plus_head *plus, int n_lines, plus_t *lines)
Allocate space for new island and create boundary info from array.
Definition: plus_area.c:634
void add_part(SYMBOL *s, SYMBPART *p)
Definition: symbol/read.c:71
int dig_add_area(struct Plus_head *plus, int n_lines, plus_t *lines)
Allocate space for new area and create boundary info from array.
Definition: plus_area.c:173
int dig_line_set_box(struct Plus_head *plus, plus_t line, BOUND_BOX *Box)
Set line bounding box.
Definition: plus_line.c:318