/*! \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]); }