simple_features.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. /*!
  2. \file lib/vector/Vlib/simple_features.c
  3. \brief Vector library - OGC Simple Features Access
  4. Higher level functions for reading/writing/manipulating vectors.
  5. Note: <b>In progress!</b> Currently on GV_POINT, GV_LINE,
  6. GV_BOUNDARY are supported.
  7. \todo
  8. - Vect_sfa_line_is_simple()
  9. - Vect_sfa_line_srid()
  10. - Vect_sfa_line_envelope()
  11. - Vect_sfa_line_asbinary()
  12. - Vect_sfa_line_is_empty()
  13. - Vect_sfa_line_is_3d()
  14. - Vect_sfa_line_is_measured()
  15. - Vect_sfa_line_boundary()
  16. Reference: http://www.opengeospatial.org/standards/sfa
  17. (C) 2009, 2011-2013 by the GRASS Development Team
  18. This program is free software under the GNU General Public License
  19. (>=v2). Read the file COPYING that comes with GRASS for details.
  20. \author Martin Landa <landa.martin gmail.com>
  21. */
  22. #include <stdio.h>
  23. #include <grass/vector.h>
  24. #include <grass/glocale.h>
  25. #ifdef HAVE_POSTGRES
  26. #include "pg_local_proto.h"
  27. #endif
  28. #ifdef HAVE_OGR
  29. #include <ogr_api.h>
  30. #endif
  31. static int check_sftype(const struct line_pnts *, int, SF_FeatureType, int);
  32. static int get_sftype(const struct line_pnts *, int, int);
  33. static void print_point(const struct line_pnts *, int, int, int, FILE *);
  34. /*!
  35. \brief Get SF type of given vector feature
  36. List of supported feature types:
  37. - GV_POINT -> SF_POINT
  38. - GV_LINE -> SF_LINESTRING
  39. - GV_LINE (closed) -> SF_LINEARRING
  40. - GV_BOUNDARY -> SF_POLYGON
  41. \param Points pointer to line_pnts structure
  42. \param type feature type (see supported types above)
  43. \param with_z WITH_Z for 3D data
  44. \return SF type identificator (see list of supported types)
  45. \return -1 on error
  46. */
  47. SF_FeatureType Vect_sfa_get_line_type(const struct line_pnts *Points, int type, int with_z)
  48. {
  49. return get_sftype(Points, type, with_z);
  50. }
  51. /*!
  52. \brief Get relevant GV type
  53. \param Map pointer to Map_info structure
  54. \param type SF geometry type (SF_POINT, SF_LINESTRING, ...)
  55. \return GV type
  56. \return -1 on error
  57. */
  58. int Vect_sfa_get_type(SF_FeatureType sftype)
  59. {
  60. switch(sftype) {
  61. case SF_POINT:
  62. case SF_POINT25D:
  63. return GV_POINT;
  64. case SF_LINESTRING:
  65. case SF_LINESTRING25D:
  66. case SF_LINEARRING:
  67. return GV_LINE;
  68. case SF_POLYGON:
  69. case SF_POLYGON25D:
  70. return GV_BOUNDARY;
  71. default:
  72. break;
  73. }
  74. return -1;
  75. }
  76. /*!
  77. \brief Check SF type
  78. E.g. if <em>type</em> is GV_LINE with two or more segments and the
  79. start node is identical with the end node, and <em>sftype</em> is
  80. SF_LINEARRING, functions returns 1, otherwise 0.
  81. \param Points pointer to line_pnts structure
  82. \param type feature type (GV_POINT, GV_LINE, ...)
  83. \param sftype SF type to be checked (SF_POINT, SF_LINE, ...)
  84. \param with_z non-zero value for 3D data
  85. \return 1 if type is sftype
  86. \return 0 type differs from sftype
  87. */
  88. int Vect_sfa_check_line_type(const struct line_pnts *Points, int type,
  89. SF_FeatureType sftype, int with_z)
  90. {
  91. return check_sftype(Points, type, sftype, with_z);
  92. }
  93. /*!
  94. \brief Get geometry dimension
  95. \param Points pointer to line_pnts structure
  96. \param type feature type (GV_POINT, GV_LINE, ...)
  97. \return 0 for GV_POINT
  98. \return 1 for GV_LINE
  99. \return 2 for GV_BOUNDARY
  100. \return -1 unsupported feature type
  101. */
  102. int Vect_sfa_line_dimension(int type)
  103. {
  104. if (type == GV_POINT)
  105. return 0;
  106. if (type == GV_LINE)
  107. return 1;
  108. if (type == GV_BOUNDARY)
  109. return 2;
  110. return -1;
  111. }
  112. /*!
  113. \brief Get geometry type (string)
  114. Supported types:
  115. - GV_POINT -> SF_POINT -> "POINT"
  116. - GV_LINE -> SF_LINESTRING -> "LINESTRING"
  117. - GV_LINE (closed) -> SF_LINEARRING -> "LINEARRING"
  118. - GV_BOUNDARY (closed) -> SF_POLYGON -> "POLYGON"
  119. Note: Allocated string should be freed by G_free().
  120. \param Points pointer to line_pnts structure (feature geometry)
  121. \param type feature type (see supported types above)
  122. \return geometry type string
  123. \return NULL unsupported feature type
  124. */
  125. char *Vect_sfa_line_geometry_type(const struct line_pnts *Points, int type)
  126. {
  127. SF_FeatureType sftype = Vect_sfa_get_line_type(Points, type, 0);
  128. if (sftype == SF_POINT)
  129. return G_store("POINT");
  130. if (sftype == SF_LINESTRING)
  131. return G_store("LINESTRING");
  132. if (sftype == SF_LINEARRING)
  133. return G_store("LINEARRING");
  134. if (sftype == SF_POLYGON)
  135. return G_store("POLYGON");
  136. return NULL;
  137. }
  138. /*!
  139. \brief Export geometry to Well-Known Text
  140. \param Points pointer to line_pnts structure
  141. \param type feature type
  142. \param with_z non-zero value for 3D data
  143. \param precision floating number precision
  144. \param[out] file file where to write the output
  145. \return 0 on success
  146. \return -1 unsupported feature type
  147. */
  148. int Vect_sfa_line_astext(const struct line_pnts *Points, int type, int with_z, int precision, FILE *file)
  149. {
  150. int i, sftype;
  151. sftype = Vect_sfa_get_line_type(Points, type, with_z);
  152. switch(sftype) {
  153. case SF_POINT: { /* point */
  154. fprintf(file, "POINT(");
  155. print_point(Points, 0, with_z, precision, file);
  156. fprintf(file, ")\n");
  157. break;
  158. }
  159. case SF_LINESTRING: case SF_LINEARRING: /* line */ {
  160. if (sftype == SF_LINESTRING)
  161. fprintf(file, "LINESTRING(");
  162. else
  163. fprintf(file, "LINEARRING(");
  164. for (i = 0; i < Points->n_points; i++) {
  165. print_point(Points, i, with_z, precision, file);
  166. if (i < Points->n_points - 1)
  167. fprintf(file, ", ");
  168. }
  169. fprintf(file, ")\n");
  170. break;
  171. }
  172. case SF_POLYGON: /* polygon */ {
  173. /* write only outter/inner ring */
  174. fprintf(file, "(");
  175. for (i = 0; i < Points->n_points; i++) {
  176. print_point(Points, i, with_z, precision, file);
  177. if (i < Points->n_points - 1)
  178. fprintf(file, ", ");
  179. }
  180. fprintf(file, ")");
  181. break;
  182. }
  183. default: {
  184. G_warning(_("Unknown Simple Features type (%d)"), sftype);
  185. return -1;
  186. }
  187. }
  188. fflush(file);
  189. return 0;
  190. }
  191. /*!
  192. \brief Check if feature is simple
  193. \param Points pointer to line_pnts structure
  194. \param type feature type (GV_POINT, GV_LINE, ...)
  195. \return 1 feature simple
  196. \return 0 feature not simple
  197. \return -1 feature type not supported (GV_POINT, GV_CENTROID, ...)
  198. */
  199. int Vect_sfa_is_line_simple(const struct line_pnts *Points, int type, int with_z)
  200. {
  201. SF_FeatureType sftype;
  202. sftype = Vect_sfa_get_line_type(Points, type, with_z);
  203. /* TODO */
  204. return 0;
  205. }
  206. /*!
  207. \brief Check if feature is closed
  208. \param Points pointer to line_pnts structure
  209. \param type feature type (GV_LINE or GV_BOUNDARY)
  210. \return 1 feature closed
  211. \return 0 feature not closed
  212. \return -1 feature type not supported (GV_POINT, GV_CENTROID, ...)
  213. */
  214. int Vect_sfa_is_line_closed(const struct line_pnts *Points, int type, int with_z)
  215. {
  216. int npoints;
  217. if (type & (GV_LINES)) {
  218. npoints = Vect_get_num_line_points(Points);
  219. if (npoints > 2 &&
  220. Points->x[0] == Points->x[npoints-1] &&
  221. Points->y[0] == Points->y[npoints-1]) {
  222. if (!with_z)
  223. return 1;
  224. if (Points->z[0] == Points->z[npoints-1])
  225. return 1;
  226. }
  227. return 0;
  228. }
  229. return -1;
  230. }
  231. /*!
  232. \brief Get number of simple features
  233. For native format or PostGIS Topology returns -1
  234. \param Map vector map
  235. \return number of features
  236. \return -1 on error
  237. */
  238. int Vect_sfa_get_num_features(const struct Map_info *Map)
  239. {
  240. int nfeat;
  241. nfeat = 0;
  242. if (Map->format == GV_FORMAT_OGR || Map->format == GV_FORMAT_OGR_DIRECT) {
  243. /* OGR */
  244. #ifdef HAVE_OGR
  245. const struct Format_info_ogr *ogr_info;
  246. ogr_info = &(Map->fInfo.ogr);
  247. if (!ogr_info->layer)
  248. return -1;
  249. return OGR_L_GetFeatureCount(ogr_info->layer, TRUE);
  250. #else
  251. G_fatal_error(_("GRASS is not compiled with OGR support"));
  252. return -1;
  253. #endif
  254. }
  255. else if (Map->format == GV_FORMAT_POSTGIS && !Map->fInfo.pg.toposchema_name) {
  256. #ifdef HAVE_POSTGRES
  257. /* PostGIS */
  258. char stmt[DB_SQL_MAX];
  259. const struct Format_info_pg *pg_info;
  260. pg_info = &(Map->fInfo.pg);
  261. if (!pg_info->conn || !pg_info->table_name) {
  262. G_warning(_("No connection defined"));
  263. return -1;
  264. }
  265. sprintf(stmt, "SELECT count(*) FROM \"%s\".\"%s\"", pg_info->schema_name,
  266. pg_info->table_name);
  267. nfeat = Vect__execute_get_value_pg(pg_info->conn, stmt);
  268. if (nfeat < 0) {
  269. G_warning(_("Unable to get number of simple features"));
  270. return -1;
  271. }
  272. #else
  273. G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
  274. return -1;
  275. #endif
  276. }
  277. else {
  278. G_warning(_("Unable to report simple features for vector map <%s>"),
  279. Vect_get_full_name(Map));
  280. return -1;
  281. }
  282. return nfeat;
  283. }
  284. int check_sftype(const struct line_pnts *points, int type,
  285. SF_FeatureType sftype, int with_z)
  286. {
  287. if (type == GV_POINT && sftype == SF_POINT) {
  288. return 1;
  289. }
  290. if (type == GV_LINE) {
  291. if (sftype == SF_LINESTRING)
  292. return 1;
  293. if (sftype == SF_LINEARRING &&
  294. Vect_sfa_is_line_closed(points, type, with_z))
  295. return 1;
  296. }
  297. if (type == GV_BOUNDARY) {
  298. if (sftype == SF_POLYGON &&
  299. Vect_sfa_is_line_closed(points, type, 0)) /* force 2D */
  300. return 1;
  301. }
  302. return 0;
  303. }
  304. int get_sftype(const struct line_pnts *points, int type, int with_z)
  305. {
  306. if (check_sftype(points, type, SF_POINT, with_z))
  307. return SF_POINT;
  308. if (check_sftype(points, type, SF_LINEARRING, with_z))
  309. return SF_LINEARRING;
  310. if (check_sftype(points, type, SF_LINESTRING, with_z))
  311. return SF_LINESTRING;
  312. if (check_sftype(points, type, SF_POLYGON, with_z))
  313. return SF_POLYGON;
  314. return -1;
  315. }
  316. void print_point(const struct line_pnts *Points, int index, int with_z, int precision, FILE *file)
  317. {
  318. fprintf(file, "%.*f %.*f", precision, Points->x[index], precision, Points->y[index]);
  319. if (with_z)
  320. fprintf(file, " %.*f", precision, Points->z[index]);
  321. }