GRASS 8 Programmer's Manual  8.5.0dev(2025)-c070206eb1
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,
65  int with_z)
66 {
67  return get_sftype(Points, type, with_z);
68 }
69 
70 /*!
71  \brief Get relevant GV type
72 
73  \param sftype 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 type feature type (GV_POINT, GV_LINE, ...)
123 
124  \return 0 for GV_POINT
125  \return 1 for GV_LINE
126  \return 2 for GV_BOUNDARY
127  \return -1 unsupported feature type
128  */
130 {
131  if (type == GV_POINT)
132  return 0;
133  if (type == GV_LINE)
134  return 1;
135  if (type == GV_BOUNDARY)
136  return 2;
137 
138  return -1;
139 }
140 
141 /*!
142  \brief Get geometry type (string)
143 
144  Supported types:
145  - GV_POINT -> SF_POINT -> "POINT"
146  - GV_LINE -> SF_LINESTRING -> "LINESTRING"
147  - GV_LINE (closed) -> SF_LINEARRING -> "LINEARRING"
148  - GV_BOUNDARY (closed) -> SF_POLYGON -> "POLYGON"
149 
150  Note: Allocated string should be freed by G_free().
151 
152  \param Points pointer to line_pnts structure (feature geometry)
153  \param type feature type (see supported types above)
154 
155  \return geometry type string
156  \return NULL unsupported feature type
157  */
158 char *Vect_sfa_line_geometry_type(const struct line_pnts *Points, int type)
159 {
160  SF_FeatureType sftype = Vect_sfa_get_line_type(Points, type, 0);
161 
162  if (sftype == SF_POINT)
163  return G_store("POINT");
164  if (sftype == SF_LINESTRING)
165  return G_store("LINESTRING");
166  if (sftype == SF_LINEARRING)
167  return G_store("LINEARRING");
168  if (sftype == SF_POLYGON)
169  return G_store("POLYGON");
170 
171  return NULL;
172 }
173 
174 /*!
175  \brief Export geometry to Well-Known Text
176 
177  \param Points pointer to line_pnts structure
178  \param type feature type
179  \param with_z non-zero value for 3D data
180  \param precision floating number precision
181  \param[out] file file where to write the output
182 
183  \return 0 on success
184  \return -1 unsupported feature type
185  */
186 int Vect_sfa_line_astext(const struct line_pnts *Points, int type, int with_z,
187  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:
201  case SF_LINEARRING: /* line */ {
202  if (sftype == SF_LINESTRING)
203  fprintf(file, "LINESTRING(");
204  else
205  fprintf(file, "LINEARRING(");
206  for (i = 0; i < Points->n_points; i++) {
207  print_point(Points, i, with_z, precision, file);
208  if (i < Points->n_points - 1)
209  fprintf(file, ", ");
210  }
211  fprintf(file, ")\n");
212  break;
213  }
214  case SF_POLYGON: /* polygon */ {
215  /* write only outer/inner ring */
216  fprintf(file, "(");
217  for (i = 0; i < Points->n_points; i++) {
218  print_point(Points, i, with_z, precision, file);
219  if (i < Points->n_points - 1)
220  fprintf(file, ", ");
221  }
222  fprintf(file, ")");
223  break;
224  }
225  default: {
226  G_warning(_("Unknown Simple Features type (%d)"), sftype);
227  return -1;
228  }
229  }
230 
231  fflush(file);
232  return 0;
233 }
234 
235 /*!
236  \brief Check if feature is simple
237 
238  \param Points pointer to line_pnts structure (unused)
239  \param type feature type (GV_POINT, GV_LINE, ...) (unused)
240  \param with_z (unused)
241 
242  \return 1 feature simple
243  \return 0 feature not simple
244  \return -1 feature type not supported (GV_POINT, GV_CENTROID, ...)
245  \note Implementation is pending, now always returns 0
246  */
247 int Vect_sfa_is_line_simple(const struct line_pnts *Points UNUSED,
248  int type UNUSED, int with_z UNUSED)
249 {
250  /* TODO:
251  SF_FeatureType sftype;
252 
253  Vect_sfa_get_line_type(Points, type, with_z);
254 
255  */
256 
257  return 0;
258 }
259 
260 /*!
261  \brief Check if feature is closed
262 
263  \param Points pointer to line_pnts structure
264  \param type feature type (GV_LINE or GV_BOUNDARY)
265  \param with_z
266 
267  \return 1 feature closed
268  \return 0 feature not closed
269  \return -1 feature type not supported (GV_POINT, GV_CENTROID, ...)
270  */
271 int Vect_sfa_is_line_closed(const struct line_pnts *Points, int type,
272  int with_z)
273 {
274  int npoints;
275 
276  if (type & (GV_LINES)) {
277  npoints = Vect_get_num_line_points(Points);
278  if (npoints > 2 && Points->x[0] == Points->x[npoints - 1] &&
279  Points->y[0] == Points->y[npoints - 1]) {
280  if (!with_z)
281  return 1;
282  if (Points->z[0] == Points->z[npoints - 1])
283  return 1;
284  }
285  return 0;
286  }
287  return -1;
288 }
289 
290 /*!
291  \brief Get number of simple features
292 
293  For native format or PostGIS Topology returns -1
294 
295  \param Map vector map
296 
297  \return number of features
298  \return -1 on error
299  */
301 {
302  int nfeat;
303 
304  nfeat = 0;
305  if (Map->format == GV_FORMAT_OGR || Map->format == GV_FORMAT_OGR_DIRECT) {
306  /* OGR */
307 #ifdef HAVE_OGR
308  const struct Format_info_ogr *ogr_info;
309 
310  ogr_info = &(Map->fInfo.ogr);
311 
312  if (!ogr_info->layer)
313  return -1;
314 
315  return OGR_L_GetFeatureCount(ogr_info->layer, TRUE);
316 #else
317  G_fatal_error(_("GRASS is not compiled with OGR support"));
318  return -1;
319 #endif
320  }
321  else if (Map->format == GV_FORMAT_POSTGIS &&
322  !Map->fInfo.pg.toposchema_name) {
323 #ifdef HAVE_POSTGRES
324  /* PostGIS */
325  char stmt[DB_SQL_MAX];
326 
327  const struct Format_info_pg *pg_info;
328 
329  pg_info = &(Map->fInfo.pg);
330 
331  if (!pg_info->conn || !pg_info->table_name) {
332  G_warning(_("No connection defined"));
333  return -1;
334  }
335 
336  snprintf(stmt, sizeof(stmt), "SELECT count(*) FROM \"%s\".\"%s\"",
337  pg_info->schema_name, pg_info->table_name);
338  nfeat = Vect__execute_get_value_pg(pg_info->conn, stmt);
339  if (nfeat < 0) {
340  G_warning(_("Unable to get number of simple features"));
341  return -1;
342  }
343 #else
344  G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
345  return -1;
346 #endif
347  }
348  else {
349  const char *map_name = Vect_get_full_name(Map);
350  G_warning(_("Unable to report simple features for vector map <%s>"),
351  map_name);
352  G_free((void *)map_name);
353  return -1;
354  }
355 
356  return nfeat;
357 }
358 
359 int check_sftype(const struct line_pnts *points, int type,
360  SF_FeatureType sftype, int with_z)
361 {
362  if (type == GV_POINT && sftype == SF_POINT) {
363  return 1;
364  }
365 
366  if (type == GV_LINE) {
367  if (sftype == SF_LINESTRING)
368  return 1;
369 
370  if (sftype == SF_LINEARRING &&
371  Vect_sfa_is_line_closed(points, type, with_z))
372  return 1;
373  }
374 
375  if (type == GV_BOUNDARY) {
376  if (sftype == SF_POLYGON &&
377  Vect_sfa_is_line_closed(points, type, 0)) /* force 2D */
378  return 1;
379  }
380 
381  return 0;
382 }
383 
384 int get_sftype(const struct line_pnts *points, int type, int with_z)
385 {
386  if (check_sftype(points, type, SF_POINT, with_z))
387  return SF_POINT;
388 
389  if (check_sftype(points, type, SF_LINEARRING, with_z))
390  return SF_LINEARRING;
391 
392  if (check_sftype(points, type, SF_LINESTRING, with_z))
393  return SF_LINESTRING;
394 
395  if (check_sftype(points, type, SF_POLYGON, with_z))
396  return SF_POLYGON;
397 
398  return -1;
399 }
400 
401 void print_point(const struct line_pnts *Points, int index, int with_z,
402  int precision, FILE *file)
403 {
404  fprintf(file, "%.*f %.*f", precision, Points->x[index], precision,
405  Points->y[index]);
406  if (with_z)
407  fprintf(file, " %.*f", precision, Points->z[index]);
408 }
#define NULL
Definition: ccmath.h:32
#define DB_SQL_MAX
Definition: dbmi.h:142
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:147
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
const char * Vect_get_full_name(struct Map_info *)
Get fully qualified name of vector map.
int Vect_get_num_line_points(const struct line_pnts *)
Get number of line points.
Definition: line.c:267
SF_FeatureType
Simple feature types.
Definition: dig_defines.h:239
@ SF_POLYGON
Definition: dig_defines.h:244
@ SF_LINESTRING
Definition: dig_defines.h:242
@ SF_POLYGON25D
Definition: dig_defines.h:256
@ SF_POINT25D
Definition: dig_defines.h:254
@ SF_POINT
Definition: dig_defines.h:241
@ SF_LINESTRING25D
Definition: dig_defines.h:255
@ SF_LINEARRING
Definition: dig_defines.h:253
#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_LINES
Definition: dig_defines.h:193
#define GV_BOUNDARY
Definition: dig_defines.h:185
#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
#define TRUE
Definition: gis.h:78
#define UNUSED
A macro for an attribute, if attached to a variable, indicating that the variable is not used.
Definition: gis.h:46
#define _(str)
Definition: glocale.h:10
#define file
int Vect__execute_get_value_pg(PGconn *conn, const char *stmt)
Execute SQL statement and get value.
Definition: read_pg.c:1599
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.
SF_FeatureType Vect_sfa_get_line_type(const struct line_pnts *Points, int type, int with_z)
Get SF type of given vector feature.
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.
int Vect_sfa_get_num_features(struct Map_info *Map)
Get number of simple features.
int Vect_sfa_is_line_closed(const struct line_pnts *Points, int type, int with_z)
Check if feature is closed.
int Vect_sfa_line_dimension(int type)
Get geometry dimension.
int Vect_sfa_is_line_simple(const struct line_pnts *Points, int type, int with_z)
Check if feature is simple.
int Vect_sfa_get_type(SF_FeatureType sftype)
Get relevant GV type.
Non-native format info (OGR)
Definition: dig_structs.h:505
OGRLayerH layer
Pointer to OGRLayer.
Definition: dig_structs.h:534
Non-native format info (PostGIS)
Definition: dig_structs.h:590
char * schema_name
Schema name.
Definition: dig_structs.h:602
PGconn * conn
PGconn object (generated by PQconnectdb)
Definition: dig_structs.h:650
char * toposchema_name
Topology schema name and id.
Definition: dig_structs.h:686
char * table_name
Table name.
Definition: dig_structs.h:606
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
Feature geometry info - coordinates.
Definition: dig_structs.h:1651
double * y
Array of Y coordinates.
Definition: dig_structs.h:1659
double * x
Array of X coordinates.
Definition: dig_structs.h:1655
int n_points
Number of points.
Definition: dig_structs.h:1667
double * z
Array of Z coordinates.
Definition: dig_structs.h:1663