GRASS GIS 8 Programmer's Manual  8.2.2dev(2023)-3d2c704037
simple_features.c
Go to the documentation of this file.
1 /*!
2  \file lib/vector/Vlib/simple_features.c
3 
4  \brief Vector library - OGC Simple Features Access
5 
6  Higher level functions for reading/writing/manipulating vectors.
7 
8  Note: <b>In progress!</b> Currently on GV_POINT, GV_LINE,
9  GV_BOUNDARY are supported.
10 
11  \todo
12  - Vect_sfa_line_is_simple()
13  - Vect_sfa_line_srid()
14  - Vect_sfa_line_envelope()
15  - Vect_sfa_line_asbinary()
16  - Vect_sfa_line_is_empty()
17  - Vect_sfa_line_is_3d()
18  - Vect_sfa_line_is_measured()
19  - Vect_sfa_line_boundary()
20 
21  Reference: http://www.opengeospatial.org/standards/sfa
22 
23  (C) 2009, 2011-2013 by the GRASS Development Team
24 
25  This program is free software under the GNU General Public License
26  (>=v2). Read the file COPYING that comes with GRASS for details.
27 
28  \author Martin Landa <landa.martin gmail.com>
29 */
30 
31 #include <stdio.h>
32 
33 #include <grass/vector.h>
34 #include <grass/glocale.h>
35 
36 #ifdef HAVE_POSTGRES
37 #include "pg_local_proto.h"
38 #endif
39 
40 #ifdef HAVE_OGR
41 #include <ogr_api.h>
42 #endif
43 
44 static int check_sftype(const struct line_pnts *, int, SF_FeatureType, int);
45 static int get_sftype(const struct line_pnts *, int, int);
46 static void print_point(const struct line_pnts *, int, int, int, FILE *);
47 
48 /*!
49  \brief Get SF type of given vector feature
50 
51  List of supported feature types:
52  - GV_POINT -> SF_POINT
53  - GV_LINE -> SF_LINESTRING
54  - GV_LINE (closed) -> SF_LINEARRING
55  - GV_BOUNDARY -> SF_POLYGON
56 
57  \param Points pointer to line_pnts structure
58  \param type feature type (see supported types above)
59  \param with_z WITH_Z for 3D data
60 
61  \return SF type identificator (see list of supported types)
62  \return -1 on error
63 */
64 SF_FeatureType Vect_sfa_get_line_type(const struct line_pnts *Points, int type, int with_z)
65 {
66  return get_sftype(Points, type, with_z);
67 }
68 
69 /*!
70  \brief Get relevant GV type
71 
72  \param Map pointer to Map_info structure
73  \param type SF geometry type (SF_POINT, SF_LINESTRING, ...)
74 
75  \return GV type
76  \return -1 on error
77  */
79 {
80  switch(sftype) {
81  case SF_POINT:
82  case SF_POINT25D:
83  return GV_POINT;
84  case SF_LINESTRING:
85  case SF_LINESTRING25D:
86  case SF_LINEARRING:
87  return GV_LINE;
88  case SF_POLYGON:
89  case SF_POLYGON25D:
90  return GV_BOUNDARY;
91  default:
92  break;
93  }
94 
95  return -1;
96 }
97 
98 /*!
99  \brief Check SF type
100 
101  E.g. if <em>type</em> is GV_LINE with two or more segments and the
102  start node is identical with the end node, and <em>sftype</em> is
103  SF_LINEARRING, functions returns 1, otherwise 0.
104 
105  \param Points pointer to line_pnts structure
106  \param type feature type (GV_POINT, GV_LINE, ...)
107  \param sftype SF type to be checked (SF_POINT, SF_LINE, ...)
108  \param with_z non-zero value for 3D data
109 
110  \return 1 if type is sftype
111  \return 0 type differs from sftype
112 */
113 int Vect_sfa_check_line_type(const struct line_pnts *Points, int type,
114  SF_FeatureType sftype, int with_z)
115 {
116  return check_sftype(Points, type, sftype, with_z);
117 }
118 
119 /*!
120  \brief Get geometry dimension
121 
122  \param Points pointer to line_pnts structure
123  \param type feature type (GV_POINT, GV_LINE, ...)
124 
125  \return 0 for GV_POINT
126  \return 1 for GV_LINE
127  \return 2 for GV_BOUNDARY
128  \return -1 unsupported feature type
129 */
131 {
132  if (type == GV_POINT)
133  return 0;
134  if (type == GV_LINE)
135  return 1;
136  if (type == GV_BOUNDARY)
137  return 2;
138 
139  return -1;
140 }
141 
142 /*!
143  \brief Get geometry type (string)
144 
145  Supported types:
146  - GV_POINT -> SF_POINT -> "POINT"
147  - GV_LINE -> SF_LINESTRING -> "LINESTRING"
148  - GV_LINE (closed) -> SF_LINEARRING -> "LINEARRING"
149  - GV_BOUNDARY (closed) -> SF_POLYGON -> "POLYGON"
150 
151  Note: Allocated string should be freed by G_free().
152 
153  \param Points pointer to line_pnts structure (feature geometry)
154  \param type feature type (see supported types above)
155 
156  \return geometry type string
157  \return NULL unsupported feature type
158 */
159 char *Vect_sfa_line_geometry_type(const struct line_pnts *Points, int type)
160 {
161  SF_FeatureType sftype = Vect_sfa_get_line_type(Points, type, 0);
162 
163  if (sftype == SF_POINT)
164  return G_store("POINT");
165  if (sftype == SF_LINESTRING)
166  return G_store("LINESTRING");
167  if (sftype == SF_LINEARRING)
168  return G_store("LINEARRING");
169  if (sftype == SF_POLYGON)
170  return G_store("POLYGON");
171 
172  return NULL;
173 }
174 
175 /*!
176  \brief Export geometry to Well-Known Text
177 
178  \param Points pointer to line_pnts structure
179  \param type feature type
180  \param with_z non-zero value for 3D data
181  \param precision floating number precision
182  \param[out] file file where to write the output
183 
184  \return 0 on success
185  \return -1 unsupported feature type
186 */
187 int Vect_sfa_line_astext(const struct line_pnts *Points, int type, int with_z, int precision, FILE *file)
188 {
189  int i, sftype;
190 
191  sftype = Vect_sfa_get_line_type(Points, type, with_z);
192 
193  switch(sftype) {
194  case SF_POINT: { /* point */
195  fprintf(file, "POINT(");
196  print_point(Points, 0, with_z, precision, file);
197  fprintf(file, ")\n");
198  break;
199  }
200  case SF_LINESTRING: case SF_LINEARRING: /* line */ {
201  if (sftype == SF_LINESTRING)
202  fprintf(file, "LINESTRING(");
203  else
204  fprintf(file, "LINEARRING(");
205  for (i = 0; i < Points->n_points; i++) {
206  print_point(Points, i, with_z, precision, file);
207  if (i < Points->n_points - 1)
208  fprintf(file, ", ");
209  }
210  fprintf(file, ")\n");
211  break;
212  }
213  case SF_POLYGON: /* polygon */ {
214  /* write only outter/inner ring */
215  fprintf(file, "(");
216  for (i = 0; i < Points->n_points; i++) {
217  print_point(Points, i, with_z, precision, file);
218  if (i < Points->n_points - 1)
219  fprintf(file, ", ");
220  }
221  fprintf(file, ")");
222  break;
223  }
224  default: {
225  G_warning(_("Unknown Simple Features type (%d)"), sftype);
226  return -1;
227  }
228  }
229 
230  fflush(file);
231  return 0;
232 }
233 
234 /*!
235  \brief Check if feature is simple
236 
237  \param Points pointer to line_pnts structure
238  \param type feature type (GV_POINT, GV_LINE, ...)
239 
240  \return 1 feature simple
241  \return 0 feature not simple
242  \return -1 feature type not supported (GV_POINT, GV_CENTROID, ...)
243 */
244 int Vect_sfa_is_line_simple(const struct line_pnts *Points, int type, int with_z)
245 {
246  SF_FeatureType sftype;
247 
248  sftype = Vect_sfa_get_line_type(Points, type, with_z);
249 
250  /* TODO */
251 
252  return 0;
253 }
254 
255 /*!
256  \brief Check if feature is closed
257 
258  \param Points pointer to line_pnts structure
259  \param type feature type (GV_LINE or GV_BOUNDARY)
260 
261  \return 1 feature closed
262  \return 0 feature not closed
263  \return -1 feature type not supported (GV_POINT, GV_CENTROID, ...)
264 */
265 int Vect_sfa_is_line_closed(const struct line_pnts *Points, int type, int with_z)
266 {
267  int npoints;
268  if (type & (GV_LINES)) {
269  npoints = Vect_get_num_line_points(Points);
270  if (npoints > 2 &&
271  Points->x[0] == Points->x[npoints-1] &&
272  Points->y[0] == Points->y[npoints-1]) {
273  if (!with_z)
274  return 1;
275  if (Points->z[0] == Points->z[npoints-1])
276  return 1;
277  }
278  return 0;
279  }
280  return -1;
281 }
282 
283 /*!
284  \brief Get number of simple features
285 
286  For native format or PostGIS Topology returns -1
287 
288  \param Map vector map
289 
290  \return number of features
291  \return -1 on error
292 */
293 int Vect_sfa_get_num_features(const struct Map_info *Map)
294 {
295  int nfeat;
296 
297  nfeat = 0;
298  if (Map->format == GV_FORMAT_OGR || Map->format == GV_FORMAT_OGR_DIRECT) {
299  /* OGR */
300 #ifdef HAVE_OGR
301  const struct Format_info_ogr *ogr_info;
302 
303  ogr_info = &(Map->fInfo.ogr);
304 
305  if (!ogr_info->layer)
306  return -1;
307 
308  return OGR_L_GetFeatureCount(ogr_info->layer, TRUE);
309 #else
310  G_fatal_error(_("GRASS is not compiled with OGR support"));
311  return -1;
312 #endif
313  }
314  else if (Map->format == GV_FORMAT_POSTGIS && !Map->fInfo.pg.toposchema_name) {
315 #ifdef HAVE_POSTGRES
316  /* PostGIS */
317  char stmt[DB_SQL_MAX];
318 
319  const struct Format_info_pg *pg_info;
320 
321  pg_info = &(Map->fInfo.pg);
322 
323  if (!pg_info->conn || !pg_info->table_name) {
324  G_warning(_("No connection defined"));
325  return -1;
326  }
327 
328  sprintf(stmt, "SELECT count(*) FROM \"%s\".\"%s\"", pg_info->schema_name,
329  pg_info->table_name);
330  nfeat = Vect__execute_get_value_pg(pg_info->conn, stmt);
331  if (nfeat < 0) {
332  G_warning(_("Unable to get number of simple features"));
333  return -1;
334  }
335 #else
336  G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
337  return -1;
338 #endif
339  }
340  else {
341  G_warning(_("Unable to report simple features for vector map <%s>"),
342  Vect_get_full_name(Map));
343  return -1;
344  }
345 
346  return nfeat;
347 }
348 
349 int check_sftype(const struct line_pnts *points, int type,
350  SF_FeatureType sftype, int with_z)
351 {
352  if (type == GV_POINT && sftype == SF_POINT) {
353  return 1;
354  }
355 
356  if (type == GV_LINE) {
357  if (sftype == SF_LINESTRING)
358  return 1;
359 
360  if (sftype == SF_LINEARRING &&
361  Vect_sfa_is_line_closed(points, type, with_z))
362  return 1;
363  }
364 
365  if (type == GV_BOUNDARY) {
366  if (sftype == SF_POLYGON &&
367  Vect_sfa_is_line_closed(points, type, 0)) /* force 2D */
368  return 1;
369  }
370 
371  return 0;
372 }
373 
374 int get_sftype(const struct line_pnts *points, int type, int with_z)
375 {
376  if (check_sftype(points, type, SF_POINT, with_z))
377  return SF_POINT;
378 
379  if (check_sftype(points, type, SF_LINEARRING, with_z))
380  return SF_LINEARRING;
381 
382  if (check_sftype(points, type, SF_LINESTRING, with_z))
383  return SF_LINESTRING;
384 
385  if (check_sftype(points, type, SF_POLYGON, with_z))
386  return SF_POLYGON;
387 
388  return -1;
389 }
390 
391 void print_point(const struct line_pnts *Points, int index, int with_z, int precision, FILE *file)
392 {
393  fprintf(file, "%.*f %.*f", precision, Points->x[index], precision, Points->y[index]);
394  if (with_z)
395  fprintf(file, " %.*f", precision, Points->z[index]);
396 }
char * toposchema_name
Topology schema name and id.
Definition: dig_structs.h:699
#define TRUE
Definition: gis.h:59
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
int Vect_sfa_is_line_closed(const struct line_pnts *Points, int type, int with_z)
Check if feature is closed.
PGconn * conn
PGconn object (generated by PQconnectdb)
Definition: dig_structs.h:663
int Vect_sfa_get_type(SF_FeatureType sftype)
Get relevant GV type.
#define DB_SQL_MAX
Definition: dbmi.h:142
int n_points
Number of points.
Definition: dig_structs.h:1692
int Vect_sfa_line_astext(const struct line_pnts *Points, int type, int with_z, int precision, FILE *file)
Export geometry to Well-Known Text.
#define GV_FORMAT_OGR
OGR format.
Definition: dig_defines.h:85
struct Format_info fInfo
Format info for non-native formats.
Definition: dig_structs.h:1415
char * table_name
Table name.
Definition: dig_structs.h:619
int Vect_sfa_get_num_features(const struct Map_info *Map)
Get number of simple features.
#define NULL
Definition: ccmath.h:32
#define GV_POINT
Feature types used in memory on run time (may change)
Definition: dig_defines.h:182
#define GV_LINE
Definition: dig_defines.h:183
double * x
Array of X coordinates.
Definition: dig_structs.h:1680
int Vect__execute_get_value_pg(PGconn *conn, const char *stmt)
Execute SQL statement and get value.
Definition: read_pg.c:1548
Feature geometry info - coordinates.
Definition: dig_structs.h:1675
int Vect_get_num_line_points(const struct line_pnts *)
Get number of line points.
Definition: line.c:269
Non-native format info (PostGIS)
Definition: dig_structs.h:602
struct Format_info_pg pg
PostGIS info.
Definition: dig_structs.h:726
#define GV_BOUNDARY
Definition: dig_defines.h:184
#define GV_FORMAT_OGR_DIRECT
OGR format (direct access)
Definition: dig_defines.h:87
Non-native format info (OGR)
Definition: dig_structs.h:516
int Vect_sfa_line_dimension(int type)
Get geometry dimension.
struct Format_info_ogr ogr
OGR info.
Definition: dig_structs.h:722
Vector map info.
Definition: dig_structs.h:1259
#define GV_FORMAT_POSTGIS
PostGIS format.
Definition: dig_defines.h:89
double * y
Array of Y coordinates.
Definition: dig_structs.h:1684
int Vect_sfa_is_line_simple(const struct line_pnts *Points, int type, int with_z)
Check if feature is simple.
const char * Vect_get_full_name(const struct Map_info *)
Get fully qualified name of vector map.
void G_warning(const char *,...) __attribute__((format(printf
#define file
SF_FeatureType Vect_sfa_get_line_type(const struct line_pnts *Points, int type, int with_z)
Get SF type of given vector feature.
double * z
Array of Z coordinates.
Definition: dig_structs.h:1688
#define _(str)
Definition: glocale.h:10
int format
Map format (native, ogr, postgis)
Definition: dig_structs.h:1271
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
#define GV_LINES
Definition: dig_defines.h:192
OGRLayerH layer
Pointer to OGRLayer.
Definition: dig_structs.h:546
char * schema_name
Schema name.
Definition: dig_structs.h:615
char * Vect_sfa_line_geometry_type(const struct line_pnts *Points, int type)
Get geometry type (string)
int Vect_sfa_check_line_type(const struct line_pnts *Points, int type, SF_FeatureType sftype, int with_z)
Check SF type.
SF_FeatureType
Simple feature types.
Definition: dig_defines.h:234