/*!
\file lib/vector/Vlib/simple_features.c
\brief Vector library - OGC Simple Features Access
Higher level functions for reading/writing/manipulating vectors.
Note: In progress! Currently on GV_POINT, GV_LINE,
GV_BOUNDARY are supported.
\todo
- Vect_sfa_line_is_simple()
- Vect_sfa_line_srid()
- Vect_sfa_line_envelope()
- Vect_sfa_line_asbinary()
- Vect_sfa_line_is_empty()
- Vect_sfa_line_is_3d()
- Vect_sfa_line_is_measured()
- Vect_sfa_line_boundary()
Reference: http://www.opengeospatial.org/standards/sfa
(C) 2009, 2011-2013 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
\author Martin Landa
*/
#include
#include
#include
#ifdef HAVE_POSTGRES
#include "pg_local_proto.h"
#endif
#ifdef HAVE_OGR
#include
#endif
static int check_sftype(const struct line_pnts *, int, SF_FeatureType, int);
static int get_sftype(const struct line_pnts *, int, int);
static void print_point(const struct line_pnts *, int, int, int, FILE *);
/*!
\brief Get SF type of given vector feature
List of supported feature types:
- GV_POINT -> SF_POINT
- GV_LINE -> SF_LINESTRING
- GV_LINE (closed) -> SF_LINEARRING
- GV_BOUNDARY -> SF_POLYGON
\param Points pointer to line_pnts structure
\param type feature type (see supported types above)
\param with_z WITH_Z for 3D data
\return SF type identificator (see list of supported types)
\return -1 on error
*/
SF_FeatureType Vect_sfa_get_line_type(const struct line_pnts *Points, int type, int with_z)
{
return get_sftype(Points, type, with_z);
}
/*!
\brief Get relevant GV type
\param Map pointer to Map_info structure
\param type SF geometry type (SF_POINT, SF_LINESTRING, ...)
\return GV type
\return -1 on error
*/
int Vect_sfa_get_type(SF_FeatureType sftype)
{
switch(sftype) {
case SF_POINT:
case SF_POINT25D:
return GV_POINT;
case SF_LINESTRING:
case SF_LINESTRING25D:
case SF_LINEARRING:
return GV_LINE;
case SF_POLYGON:
case SF_POLYGON25D:
return GV_BOUNDARY;
default:
break;
}
return -1;
}
/*!
\brief Check SF type
E.g. if type is GV_LINE with two or more segments and the
start node is identical with the end node, and sftype is
SF_LINEARRING, functions returns 1, otherwise 0.
\param Points pointer to line_pnts structure
\param type feature type (GV_POINT, GV_LINE, ...)
\param sftype SF type to be checked (SF_POINT, SF_LINE, ...)
\param with_z non-zero value for 3D data
\return 1 if type is sftype
\return 0 type differs from sftype
*/
int Vect_sfa_check_line_type(const struct line_pnts *Points, int type,
SF_FeatureType sftype, int with_z)
{
return check_sftype(Points, type, sftype, with_z);
}
/*!
\brief Get geometry dimension
\param Points pointer to line_pnts structure
\param type feature type (GV_POINT, GV_LINE, ...)
\return 0 for GV_POINT
\return 1 for GV_LINE
\return 2 for GV_BOUNDARY
\return -1 unsupported feature type
*/
int Vect_sfa_line_dimension(int type)
{
if (type == GV_POINT)
return 0;
if (type == GV_LINE)
return 1;
if (type == GV_BOUNDARY)
return 2;
return -1;
}
/*!
\brief Get geometry type (string)
Supported types:
- GV_POINT -> SF_POINT -> "POINT"
- GV_LINE -> SF_LINESTRING -> "LINESTRING"
- GV_LINE (closed) -> SF_LINEARRING -> "LINEARRING"
- GV_BOUNDARY (closed) -> SF_POLYGON -> "POLYGON"
Note: Allocated string should be freed by G_free().
\param Points pointer to line_pnts structure (feature geometry)
\param type feature type (see supported types above)
\return geometry type string
\return NULL unsupported feature type
*/
char *Vect_sfa_line_geometry_type(const struct line_pnts *Points, int type)
{
SF_FeatureType sftype = Vect_sfa_get_line_type(Points, type, 0);
if (sftype == SF_POINT)
return G_store("POINT");
if (sftype == SF_LINESTRING)
return G_store("LINESTRING");
if (sftype == SF_LINEARRING)
return G_store("LINEARRING");
if (sftype == SF_POLYGON)
return G_store("POLYGON");
return NULL;
}
/*!
\brief Export geometry to Well-Known Text
\param Points pointer to line_pnts structure
\param type feature type
\param with_z non-zero value for 3D data
\param precision floating number precision
\param[out] file file where to write the output
\return 0 on success
\return -1 unsupported feature type
*/
int Vect_sfa_line_astext(const struct line_pnts *Points, int type, int with_z, int precision, FILE *file)
{
int i, sftype;
sftype = Vect_sfa_get_line_type(Points, type, with_z);
switch(sftype) {
case SF_POINT: { /* point */
fprintf(file, "POINT(");
print_point(Points, 0, with_z, precision, file);
fprintf(file, ")\n");
break;
}
case SF_LINESTRING: case SF_LINEARRING: /* line */ {
if (sftype == SF_LINESTRING)
fprintf(file, "LINESTRING(");
else
fprintf(file, "LINEARRING(");
for (i = 0; i < Points->n_points; i++) {
print_point(Points, i, with_z, precision, file);
if (i < Points->n_points - 1)
fprintf(file, ", ");
}
fprintf(file, ")\n");
break;
}
case SF_POLYGON: /* polygon */ {
/* write only outter/inner ring */
fprintf(file, "(");
for (i = 0; i < Points->n_points; i++) {
print_point(Points, i, with_z, precision, file);
if (i < Points->n_points - 1)
fprintf(file, ", ");
}
fprintf(file, ")");
break;
}
default: {
G_warning(_("Unknown Simple Features type (%d)"), sftype);
return -1;
}
}
fflush(file);
return 0;
}
/*!
\brief Check if feature is simple
\param Points pointer to line_pnts structure
\param type feature type (GV_POINT, GV_LINE, ...)
\return 1 feature simple
\return 0 feature not simple
\return -1 feature type not supported (GV_POINT, GV_CENTROID, ...)
*/
int Vect_sfa_is_line_simple(const struct line_pnts *Points, int type, int with_z)
{
SF_FeatureType sftype;
sftype = Vect_sfa_get_line_type(Points, type, with_z);
/* TODO */
return 0;
}
/*!
\brief Check if feature is closed
\param Points pointer to line_pnts structure
\param type feature type (GV_LINE or GV_BOUNDARY)
\return 1 feature closed
\return 0 feature not closed
\return -1 feature type not supported (GV_POINT, GV_CENTROID, ...)
*/
int Vect_sfa_is_line_closed(const struct line_pnts *Points, int type, int with_z)
{
int npoints;
if (type & (GV_LINES)) {
npoints = Vect_get_num_line_points(Points);
if (npoints > 2 &&
Points->x[0] == Points->x[npoints-1] &&
Points->y[0] == Points->y[npoints-1]) {
if (!with_z)
return 1;
if (Points->z[0] == Points->z[npoints-1])
return 1;
}
return 0;
}
return -1;
}
/*!
\brief Get number of simple features
For native format or PostGIS Topology returns -1
\param Map vector map
\return number of features
\return -1 on error
*/
int Vect_sfa_get_num_features(const struct Map_info *Map)
{
int nfeat;
nfeat = 0;
if (Map->format == GV_FORMAT_OGR || Map->format == GV_FORMAT_OGR_DIRECT) {
/* OGR */
#ifdef HAVE_OGR
const struct Format_info_ogr *ogr_info;
ogr_info = &(Map->fInfo.ogr);
if (!ogr_info->layer)
return -1;
return OGR_L_GetFeatureCount(ogr_info->layer, TRUE);
#else
G_fatal_error(_("GRASS is not compiled with OGR support"));
return -1;
#endif
}
else if (Map->format == GV_FORMAT_POSTGIS && !Map->fInfo.pg.toposchema_name) {
#ifdef HAVE_POSTGRES
/* PostGIS */
char stmt[DB_SQL_MAX];
const struct Format_info_pg *pg_info;
pg_info = &(Map->fInfo.pg);
if (!pg_info->conn || !pg_info->table_name) {
G_warning(_("No connection defined"));
return -1;
}
sprintf(stmt, "SELECT count(*) FROM \"%s\".\"%s\"", pg_info->schema_name,
pg_info->table_name);
nfeat = Vect__execute_get_value_pg(pg_info->conn, stmt);
if (nfeat < 0) {
G_warning(_("Unable to get number of simple features"));
return -1;
}
#else
G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
return -1;
#endif
}
else {
G_warning(_("Unable to report simple features for vector map <%s>"),
Vect_get_full_name(Map));
return -1;
}
return nfeat;
}
int check_sftype(const struct line_pnts *points, int type,
SF_FeatureType sftype, int with_z)
{
if (type == GV_POINT && sftype == SF_POINT) {
return 1;
}
if (type == GV_LINE) {
if (sftype == SF_LINESTRING)
return 1;
if (sftype == SF_LINEARRING &&
Vect_sfa_is_line_closed(points, type, with_z))
return 1;
}
if (type == GV_BOUNDARY) {
if (sftype == SF_POLYGON &&
Vect_sfa_is_line_closed(points, type, 0)) /* force 2D */
return 1;
}
return 0;
}
int get_sftype(const struct line_pnts *points, int type, int with_z)
{
if (check_sftype(points, type, SF_POINT, with_z))
return SF_POINT;
if (check_sftype(points, type, SF_LINEARRING, with_z))
return SF_LINEARRING;
if (check_sftype(points, type, SF_LINESTRING, with_z))
return SF_LINESTRING;
if (check_sftype(points, type, SF_POLYGON, with_z))
return SF_POLYGON;
return -1;
}
void print_point(const struct line_pnts *Points, int index, int with_z, int precision, FILE *file)
{
fprintf(file, "%.*f %.*f", precision, Points->x[index], precision, Points->y[index]);
if (with_z)
fprintf(file, " %.*f", precision, Points->z[index]);
}