PostGIS  3.7.0dev-r@@SVN_REVISION@@
lwgeom_in_gml.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright 2009 - 2010 Oslandia
22  *
23  **********************************************************************/
24 
25 
49 #include "postgres.h"
50 #include "executor/spi.h"
51 #include "utils/builtins.h"
52 
53 #include <libxml/tree.h>
54 #include <libxml/parser.h>
55 #include <libxml/xpath.h>
56 #include <libxml/xpathInternals.h>
57 
58 #include "../postgis_config.h"
59 #include "lwgeom_pg.h"
60 #include "liblwgeom.h"
61 #include "lwgeom_transform.h"
62 
63 
64 Datum geom_from_gml(PG_FUNCTION_ARGS);
65 static LWGEOM *lwgeom_from_gml(const char *wkt, int xml_size);
66 static LWGEOM* parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid);
67 
68 typedef struct struct_gmlSrs
69 {
70  int32_t srid;
72 }
74 
75 #define XLINK_NS ((char *) "http://www.w3.org/1999/xlink")
76 #define GML_NS ((char *) "http://www.opengis.net/gml")
77 #define GML32_NS ((char *) "http://www.opengis.net/gml/3.2")
78 
79 
80 
81 static void gml_lwpgerror(char *msg, __attribute__((__unused__)) int error_code)
82 {
83  POSTGIS_DEBUGF(3, "ST_GeomFromGML ERROR %i", error_code);
84  lwpgerror("%s", msg);
85 }
86 
97 Datum geom_from_gml(PG_FUNCTION_ARGS)
98 {
99  GSERIALIZED *geom;
100  text *xml_input;
101  LWGEOM *lwgeom;
102  char *xml;
103  int root_srid=SRID_UNKNOWN;
104  int xml_size;
105 
106  /* Get the GML stream */
107  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
108  xml_input = PG_GETARG_TEXT_P(0);
109  xml = text_to_cstring(xml_input);
110  xml_size = VARSIZE_ANY_EXHDR(xml_input);
111 
112  /* Zero for undefined */
113  root_srid = PG_GETARG_INT32(1);
114 
115  lwgeom = lwgeom_from_gml(xml, xml_size);
116  if ( root_srid != SRID_UNKNOWN )
117  lwgeom->srid = root_srid;
118 
119  geom = geometry_serialize(lwgeom);
120  lwgeom_free(lwgeom);
121 
122  PG_RETURN_POINTER(geom);
123 }
124 
125 
126 static inline bool
127 is_gml_element(xmlNodePtr xn, const char *gml_name)
128 {
129  const char *colon_pos;
130  const char *node_name;
131 
132  /* Not an element node, can't do anything */
133  if (!xn || xn->type != XML_ELEMENT_NODE)
134  return false;
135 
136  /* If there's a colon in the element name, */
137  /* move past it before checking for equality with */
138  /* the element name we are looking for */
139  node_name = (const char*)xn->name;
140  colon_pos = strchr(node_name, ':');
141  if (colon_pos)
142  node_name = colon_pos + 1;
143 
144  return strcmp(node_name, gml_name) == 0;
145 }
146 
147 
152 static bool is_gml_namespace(xmlNodePtr xnode, bool is_strict)
153 {
154  xmlNsPtr *ns, *p;
155 
156  ns = xmlGetNsList(xnode->doc, xnode);
157  /*
158  * If no namespace is available we could return true anyway
159  * (because we work only on GML fragment, we don't want to
160  * 'oblige' to add namespace on the geometry root node)
161  */
162  if (ns == NULL) { return !is_strict; }
163 
164  /*
165  * Handle namespaces:
166  * - http://www.opengis.net/gml (GML 3.1.1 and priors)
167  * - http://www.opengis.net/gml/3.2 (GML 3.2.1)
168  */
169  for (p=ns ; *p ; p++)
170  {
171  if ((*p)->href == NULL || (*p)->prefix == NULL ||
172  xnode->ns == NULL || xnode->ns->prefix == NULL) continue;
173 
174  if (!xmlStrcmp(xnode->ns->prefix, (*p)->prefix))
175  {
176  if ( !strcmp((char *) (*p)->href, GML_NS)
177  || !strcmp((char *) (*p)->href, GML32_NS))
178  {
179  xmlFree(ns);
180  return true;
181  } else {
182  xmlFree(ns);
183  return false;
184  }
185  }
186  }
187 
188  xmlFree(ns);
189  return !is_strict; /* Same reason here to not return false */
190 }
191 
192 
197 static xmlChar *gmlGetProp(xmlNodePtr xnode, const char *charProp)
198 {
199  xmlChar *value;
200  xmlChar *prop = (xmlChar*)charProp;
201 
202  if (!is_gml_namespace(xnode, true))
203  return xmlGetProp(xnode, prop);
204  /*
205  * Handle namespaces:
206  * - http://www.opengis.net/gml (GML 3.1.1 and priors)
207  * - http://www.opengis.net/gml/3.2 (GML 3.2.1)
208  */
209  value = xmlGetNsProp(xnode, prop, (xmlChar *) GML_NS);
210  if (value == NULL) value = xmlGetNsProp(xnode, prop, (xmlChar *) GML32_NS);
211 
212  /* In last case try without explicit namespace */
213  if (value == NULL) value = xmlGetNoNsProp(xnode, prop);
214 
215  return value;
216 }
217 
218 
223 static bool is_xlink(xmlNodePtr node)
224 {
225  xmlChar *prop;
226 
227  prop = xmlGetNsProp(node, (xmlChar *)"type", (xmlChar *) XLINK_NS);
228  if (prop == NULL) return false;
229  if (strcmp((char *) prop, "simple"))
230  {
231  xmlFree(prop);
232  return false;
233  }
234 
235  prop = xmlGetNsProp(node, (xmlChar *)"href", (xmlChar *) XLINK_NS);
236  if (prop == NULL) return false;
237  if (prop[0] != '#')
238  {
239  xmlFree(prop);
240  return false;
241  }
242  xmlFree(prop);
243 
244  return true;
245 }
246 
247 
251 static xmlNodePtr get_xlink_node(xmlNodePtr xnode)
252 {
253  char *id;
254  xmlNsPtr *ns, *n;
255  xmlXPathContext *ctx;
256  xmlXPathObject *xpath;
257  xmlNodePtr node, ret_node;
258  xmlChar *href, *p, *node_id;
259 
260  href = xmlGetNsProp(xnode, (xmlChar *)"href", (xmlChar *) XLINK_NS);
261  p = href;
262  p++; /* ignore '#' first char */
263 
264  if (xnode->ns)
265  {
266  id = lwalloc((xmlStrlen(xnode->ns->prefix) * 2 + xmlStrlen(xnode->name) +
267  xmlStrlen(href) + sizeof("//:[@:id='']") + 1));
268  /* XPath pattern look like: //gml:point[@gml:id='p1'] */
269  sprintf(id, "//%s:%s[@%s:id='%s']",
270  (char *) xnode->ns->prefix,
271  (char *) xnode->name,
272  (char *) xnode->ns->prefix,
273  (char *) p);
274  }
275  else
276  {
277  id = lwalloc((xmlStrlen(xnode->name) +
278  xmlStrlen(href) + sizeof("//:[@:id='']") + 1));
279  /* XPath pattern look like: //gml:point[@gml:id='p1'] */
280  sprintf(id, "//%s[@id='%s']",
281  (char *) xnode->name,
282  (char *) p);
283  }
284 
285  ctx = xmlXPathNewContext(xnode->doc);
286  if (ctx == NULL)
287  {
288  xmlFree(href);
289  lwfree(id);
290  return NULL;
291  }
292 
293  /* Handle namespaces */
294  ns = xmlGetNsList(xnode->doc, xnode);
295  for (n=ns ; *n; n++) xmlXPathRegisterNs(ctx, (*n)->prefix, (*n)->href);
296  xmlFree(ns);
297 
298  /* Execute XPath expression */
299  xpath = xmlXPathEvalExpression((xmlChar *) id, ctx);
300  lwfree(id);
301  if (xpath == NULL || xpath->nodesetval == NULL || xpath->nodesetval->nodeNr != 1)
302  {
303  xmlFree(href);
304  xmlXPathFreeObject(xpath);
305  xmlXPathFreeContext(ctx);
306  return NULL;
307  }
308  ret_node = xpath->nodesetval->nodeTab[0];
309  xmlXPathFreeObject(xpath);
310  xmlXPathFreeContext(ctx);
311 
312  /* Protection against circular calls */
313  for (node = xnode ; node != NULL ; node = node->parent)
314  {
315  if (node->type != XML_ELEMENT_NODE) continue;
316  node_id = gmlGetProp(node, "id");
317  if (node_id != NULL)
318  {
319  if (!xmlStrcmp(node_id, p))
320  gml_lwpgerror("invalid GML representation", 2);
321  xmlFree(node_id);
322  }
323  }
324 
325  xmlFree(href);
326  return ret_node;
327 }
328 
329 
330 
335 static POINTARRAY *
336 gml_reproject_pa(POINTARRAY *pa, int32_t epsg_in, int32_t epsg_out)
337 {
338  LWPROJ *lwp;
339  char text_in[16];
340  char text_out[16];
341 
342  if (epsg_in == SRID_UNKNOWN)
343  return pa; /* nothing to do */
344 
345  if (epsg_out == SRID_UNKNOWN)
346  {
347  gml_lwpgerror("invalid GML representation", 3);
348  return NULL;
349  }
350 
351  snprintf(text_in, 16, "EPSG:%d", epsg_in);
352  snprintf(text_out, 16, "EPSG:%d", epsg_out);
353 
354 
355  lwp = lwproj_from_str(text_in, text_out);
356  if (!lwp)
357  {
358  gml_lwpgerror("Could not create LWPROJ*", 57);
359  return NULL;
360  }
361 
362  if (ptarray_transform(pa, lwp) == LW_FAILURE)
363  {
364  elog(ERROR, "gml_reproject_pa: reprojection failed");
365  return NULL;
366  }
367  proj_destroy(lwp->pj);
368  pfree(lwp);
369 
370  return pa;
371 }
372 
378 static int
380 {
381  char *srtext;
382  char query[256];
383  int is_axis_order_gis_friendly, err;
384 
385  if (SPI_OK_CONNECT != SPI_connect ())
386  lwpgerror("gml_is_srs_axis_order_gis_friendly: could not connect to SPI manager");
387 
388  sprintf(query, "SELECT srtext \
389  FROM spatial_ref_sys WHERE srid='%d'", srid);
390 
391  err = SPI_exec(query, 1);
392  if (err < 0) lwpgerror("gml_is_srs_axis_order_gis_friendly: error executing query %d", err);
393 
394  /* No entry in spatial_ref_sys */
395  if (SPI_processed <= 0)
396  {
397  SPI_finish();
398  return -1;
399  }
400 
401  srtext = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1);
402 
403  is_axis_order_gis_friendly = 1;
404  if (srtext && srtext[0] != '\0')
405  {
406  char* ptr;
407  char* srtext_horizontal = (char*) malloc(strlen(srtext) + 1);
408  strcpy(srtext_horizontal, srtext);
409 
410  /* Remove the VERT_CS part if we are in a COMPD_CS */
411  ptr = strstr(srtext_horizontal, ",VERT_CS[");
412  if (ptr)
413  *ptr = '\0';
414 
415  if( strstr(srtext_horizontal, "AXIS[") == NULL &&
416  strstr(srtext_horizontal, "GEOCCS[") == NULL )
417  {
418  /* If there is no axis definition, then due to how GDAL < 3
419  * generated the WKT, this means that the axis order is not
420  * GIS friendly */
421  is_axis_order_gis_friendly = 0;
422  }
423  else if( strstr(srtext_horizontal,
424  "AXIS[\"Latitude\",NORTH],AXIS[\"Longitude\",EAST]") != NULL )
425  {
426  is_axis_order_gis_friendly = 0;
427  }
428  else if( strstr(srtext_horizontal,
429  "AXIS[\"Northing\",NORTH],AXIS[\"Easting\",EAST]") != NULL )
430  {
431  is_axis_order_gis_friendly = 0;
432  }
433  else if( strstr(srtext_horizontal,
434  "AXIS[\"geodetic latitude (Lat)\",north,ORDER[1]") != NULL )
435  {
436  is_axis_order_gis_friendly = 0;
437  }
438 
439  free(srtext_horizontal);
440  }
441  SPI_finish();
442 
443  return is_axis_order_gis_friendly;
444 }
445 
446 
450 static void parse_gml_srs(xmlNodePtr xnode, gmlSrs *srs)
451 {
452  char *p;
453  int is_axis_order_gis_friendly;
454  xmlNodePtr node;
455  xmlChar *srsname;
456  bool honours_authority_axis_order = false;
457  char sep = ':';
458 
459  node = xnode;
460  srsname = gmlGetProp(node, "srsName");
461  /*printf("srsname %s\n",srsname);*/
462  if (!srsname)
463  {
464  if (node->parent == NULL)
465  {
466  srs->srid = SRID_UNKNOWN;
467  srs->reverse_axis = false;
468  return;
469  }
470  parse_gml_srs(node->parent, srs);
471  }
472  else
473  {
474  /* Severals srsName formats are available...
475  * cf WFS 1.1.0 -> 9.2 (p36)
476  * cf ISO 19142:2009 -> 7.9.2.4.4 (p34)
477  * cf RFC 5165 <http://tools.ietf.org/html/rfc5165>
478  * cf CITE WFS-1.1 (GetFeature-tc17.2)
479  */
480 
481  /* SRS pattern like: EPSG:4326
482  urn:EPSG:geographicCRS:4326
483  urn:ogc:def:crs:EPSG:4326
484  urn:ogc:def:crs:EPSG::4326
485  urn:ogc:def:crs:EPSG:6.6:4326
486  urn:x-ogc:def:crs:EPSG:6.6:4326
487  http://www.opengis.net/gml/srs/epsg.xml#4326
488  http://www.epsg.org/6.11.2/4326
489  */
490 
491  if (!strncmp((char *) srsname, "EPSG:", 5))
492  {
493  sep = ':';
494  honours_authority_axis_order = false;
495  }
496  else if (!strncmp((char *) srsname, "urn:ogc:def:crs:EPSG:", 21)
497  || !strncmp((char *) srsname, "urn:x-ogc:def:crs:EPSG:", 23)
498  || !strncmp((char *) srsname, "urn:EPSG:geographicCRS:", 23))
499  {
500  sep = ':';
501  honours_authority_axis_order = true;
502  }
503  else if (!strncmp((char *) srsname,
504  "http://www.opengis.net/gml/srs/epsg.xml#", 40))
505  {
506  sep = '#';
507  honours_authority_axis_order = false;
508  }
509  else gml_lwpgerror("unknown spatial reference system", 4);
510 
511  /* retrieve the last ':' or '#' char */
512  for (p = (char *) srsname ; *p ; p++);
513  for (--p ; *p != sep ; p--)
514  if (!isdigit(*p)) gml_lwpgerror("unknown spatial reference system", 5);
515 
516  srs->srid = atoi(++p);
517 
518  /* Check into spatial_ref_sys that this SRID really exist */
519  is_axis_order_gis_friendly = gml_is_srs_axis_order_gis_friendly(srs->srid);
520  if (srs->srid == SRID_UNKNOWN || is_axis_order_gis_friendly == -1)
521  gml_lwpgerror("unknown spatial reference system", 6);
522 
523  /* Reverse axis order if the srsName is meant to honour the axis
524  order defined by the authority and if that axis order is not
525  the GIS friendly one. */
526  srs->reverse_axis = !is_axis_order_gis_friendly && honours_authority_axis_order;
527 
528  xmlFree(srsname);
529  return;
530  }
531 }
532 
533 
537 static double parse_gml_double(char *d, bool space_before, bool space_after)
538 {
539  char *p;
540  int st;
541  enum states
542  {
543  INIT = 0,
544  NEED_DIG = 1,
545  DIG = 2,
546  NEED_DIG_DEC = 3,
547  DIG_DEC = 4,
548  EXP = 5,
549  NEED_DIG_EXP = 6,
550  DIG_EXP = 7,
551  END = 8
552  };
553 
554  /*
555  * Double pattern
556  * [-|\+]?[0-9]+(\.)?([0-9]+)?([Ee](\+|-)?[0-9]+)?
557  * We could also meet spaces before and/or after
558  * this pattern upon parameters
559  */
560 
561  if (space_before) while (isspace(*d)) d++;
562  for (st = INIT, p = d ; *p ; p++)
563  {
564 
565  if (isdigit(*p))
566  {
567  if (st == INIT || st == NEED_DIG) st = DIG;
568  else if (st == NEED_DIG_DEC) st = DIG_DEC;
569  else if (st == NEED_DIG_EXP || st == EXP) st = DIG_EXP;
570  else if (st == DIG || st == DIG_DEC || st == DIG_EXP);
571  else gml_lwpgerror("invalid GML representation", 7);
572  }
573  else if (*p == '.')
574  {
575  if (st == DIG) st = NEED_DIG_DEC;
576  else gml_lwpgerror("invalid GML representation", 8);
577  }
578  else if (*p == '-' || *p == '+')
579  {
580  if (st == INIT) st = NEED_DIG;
581  else if (st == EXP) st = NEED_DIG_EXP;
582  else gml_lwpgerror("invalid GML representation", 9);
583  }
584  else if (*p == 'e' || *p == 'E')
585  {
586  if (st == DIG || st == DIG_DEC) st = EXP;
587  else gml_lwpgerror("invalid GML representation", 10);
588  }
589  else if (isspace(*p))
590  {
591  if (!space_after) gml_lwpgerror("invalid GML representation", 11);
592  if (st == DIG || st == DIG_DEC || st == DIG_EXP)st = END;
593  else if (st == NEED_DIG_DEC) st = END;
594  else if (st == END);
595  else gml_lwpgerror("invalid GML representation", 12);
596  }
597  else gml_lwpgerror("invalid GML representation", 13);
598  }
599 
600  if (st != DIG && st != NEED_DIG_DEC && st != DIG_DEC && st != DIG_EXP && st != END)
601  gml_lwpgerror("invalid GML representation", 14);
602 
603  return atof(d);
604 }
605 
606 
610 static POINTARRAY* parse_gml_coordinates(xmlNodePtr xnode, bool *hasz)
611 {
612  xmlChar *gml_coord, *gml_ts, *gml_cs, *gml_dec;
613  char cs, ts, dec;
614  POINTARRAY *dpa;
615  int gml_dims;
616  char *p, *q;
617  bool digit;
618  POINT4D pt = {0};
619 
620  /* We begin to retrieve coordinates string */
621  gml_coord = xmlNodeGetContent(xnode);
622  p = (char *) gml_coord;
623 
624  /* Default GML coordinates pattern: x1,y1 x2,y2
625  * x1,y1,z1 x2,y2,z2
626  *
627  * Cf GML 2.1.2 -> 4.3.1 (p18)
628  */
629 
630  /* Retrieve separator between coordinates tuples */
631  gml_ts = gmlGetProp(xnode, "ts");
632  if (gml_ts == NULL) ts = ' ';
633  else
634  {
635  if (xmlStrlen(gml_ts) > 1 || isdigit(gml_ts[0]))
636  gml_lwpgerror("invalid GML representation", 15);
637  ts = gml_ts[0];
638  xmlFree(gml_ts);
639  }
640 
641  /* Retrieve separator between each coordinate */
642  gml_cs = gmlGetProp(xnode, "cs");
643  if (gml_cs == NULL) cs = ',';
644  else
645  {
646  if (xmlStrlen(gml_cs) > 1 || isdigit(gml_cs[0]))
647  gml_lwpgerror("invalid GML representation", 16);
648  cs = gml_cs[0];
649  xmlFree(gml_cs);
650  }
651 
652  /* Retrieve decimal separator */
653  gml_dec = gmlGetProp(xnode, "decimal");
654  if (gml_dec == NULL) dec = '.';
655  else
656  {
657  if (xmlStrlen(gml_dec) > 1 || isdigit(gml_dec[0]))
658  gml_lwpgerror("invalid GML representation", 17);
659  dec = gml_dec[0];
660  xmlFree(gml_dec);
661  }
662 
663  if (cs == ts || cs == dec || ts == dec)
664  gml_lwpgerror("invalid GML representation", 18);
665 
666  /* HasZ, !HasM, 1 Point */
667  dpa = ptarray_construct_empty(1, 0, 1);
668 
669  while (isspace(*p)) p++; /* Eat extra whitespaces if any */
670  for (q = p, gml_dims=0, digit = false ; *p ; p++)
671  {
672 
673  if (isdigit(*p)) digit = true; /* One state parser */
674 
675  /* Coordinate Separator */
676  if (*p == cs)
677  {
678  *p = '\0';
679  gml_dims++;
680 
681  if (*(p+1) == '\0') gml_lwpgerror("invalid GML representation", 19);
682 
683  if (gml_dims == 1) pt.x = parse_gml_double(q, false, true);
684  else if (gml_dims == 2) pt.y = parse_gml_double(q, false, true);
685 
686  q = p+1;
687 
688  /* Tuple Separator (or end string) */
689  }
690  else if (digit && (*p == ts || *(p+1) == '\0'))
691  {
692  if (*p == ts) *p = '\0';
693  gml_dims++;
694 
695  if (gml_dims < 2 || gml_dims > 3)
696  gml_lwpgerror("invalid GML representation", 20);
697 
698  if (gml_dims == 3)
699  pt.z = parse_gml_double(q, false, true);
700  else
701  {
702  pt.y = parse_gml_double(q, false, true);
703  *hasz = false;
704  }
705 
706  ptarray_append_point(dpa, &pt, LW_TRUE);
707  digit = false;
708 
709  q = p+1;
710  gml_dims = 0;
711 
712  /* Need to put standard decimal separator to atof handle */
713  }
714  else if (*p == dec && dec != '.') *p = '.';
715  }
716 
717  xmlFree(gml_coord);
718 
719  return dpa; /* ptarray_clone_deep(dpa); */
720 }
721 
722 
726 static POINTARRAY* parse_gml_coord(xmlNodePtr xnode, bool *hasz)
727 {
728  xmlNodePtr xyz;
729  POINTARRAY *dpa;
730  bool x,y,z;
731  xmlChar *c;
732  POINT4D p = {0};
733 
734  /* HasZ?, !HasM, 1 Point */
735  dpa = ptarray_construct_empty(1, 0, 1);
736 
737  x = y = z = false;
738  for (xyz = xnode->children ; xyz != NULL ; xyz = xyz->next)
739  {
740  if (xyz->type != XML_ELEMENT_NODE) continue;
741  if (!is_gml_namespace(xyz, false)) continue;
742 
743  if (is_gml_element(xyz, "X"))
744  {
745  if (x) gml_lwpgerror("invalid GML representation", 21);
746  c = xmlNodeGetContent(xyz);
747  p.x = parse_gml_double((char *) c, true, true);
748  x = true;
749  xmlFree(c);
750  }
751  else if (is_gml_element(xyz, "Y"))
752  {
753  if (y) gml_lwpgerror("invalid GML representation", 22);
754  c = xmlNodeGetContent(xyz);
755  p.y = parse_gml_double((char *) c, true, true);
756  y = true;
757  xmlFree(c);
758  }
759  else if (is_gml_element(xyz, "Z"))
760  {
761  if (z) gml_lwpgerror("invalid GML representation", 23);
762  c = xmlNodeGetContent(xyz);
763  p.z = parse_gml_double((char *) c, true, true);
764  z = true;
765  xmlFree(c);
766  }
767  }
768  /* Check dimension consistency */
769  if (!x || !y) gml_lwpgerror("invalid GML representation", 24);
770  if (!z) *hasz = false;
771 
772  ptarray_append_point(dpa, &p, LW_FALSE);
773 
774  return dpa; /* ptarray_clone_deep(dpa); */
775 }
776 
777 
781 static POINTARRAY* parse_gml_pos(xmlNodePtr xnode, bool *hasz)
782 {
783  xmlChar *dimension, *gmlpos;
784  int dim, gml_dim;
785  POINTARRAY *dpa;
786  char *pos, *p;
787  bool digit;
788  POINT4D pt = {0, 0, 0, 0};
789 
790  /* HasZ, !HasM, 1 Point */
791  dpa = ptarray_construct_empty(1, 0, 1);
792 
793  dimension = gmlGetProp(xnode, "srsDimension");
794  if (dimension == NULL) /* in GML 3.0.0 it was dimension */
795  dimension = gmlGetProp(xnode, "dimension");
796  if (dimension == NULL) dim = 2; /* We assume that we are in 2D */
797  else
798  {
799  dim = atoi((char *) dimension);
800  xmlFree(dimension);
801  if (dim < 2 || dim > 3)
802  gml_lwpgerror("invalid GML representation", 25);
803  }
804  if (dim == 2) *hasz = false;
805 
806  /* We retrieve gml:pos string */
807  gmlpos = xmlNodeGetContent(xnode);
808  pos = (char *) gmlpos;
809  while (isspace(*pos)) pos++; /* Eat extra whitespaces if any */
810 
811  /* gml:pos pattern: x1 y1
812  * x1 y1 z1
813  */
814  for (p=pos, gml_dim=0, digit=false ; *pos ; pos++)
815  {
816  if (isdigit(*pos)) digit = true;
817  if (digit && (*pos == ' ' || *(pos+1) == '\0'))
818  {
819  if (*pos == ' ') *pos = '\0';
820  gml_dim++;
821  if (gml_dim == 1)
822  pt.x = parse_gml_double(p, true, true);
823  else if (gml_dim == 2)
824  pt.y = parse_gml_double(p, true, true);
825  else if (gml_dim == 3)
826  pt.z = parse_gml_double(p, true, true);
827 
828  p = pos+1;
829  digit = false;
830  }
831  }
832  xmlFree(gmlpos);
833 
834  /* Test again coherent dimensions on each coord */
835  if (gml_dim == 2) *hasz = false;
836  if (gml_dim < 2 || gml_dim > 3 || gml_dim != dim)
837  gml_lwpgerror("invalid GML representation", 26);
838 
839  ptarray_append_point(dpa, &pt, LW_FALSE);
840 
841  return dpa; /* ptarray_clone_deep(dpa); */
842 }
843 
844 
848 static POINTARRAY* parse_gml_poslist(xmlNodePtr xnode, bool *hasz)
849 {
850  xmlChar *dimension, *gmlposlist;
851  char *poslist, *p;
852  int dim, gml_dim;
853  POINTARRAY *dpa;
854  POINT4D pt = {0, 0, 0, 0};
855  bool digit;
856 
857  /* Retrieve gml:srsDimension attribute if any */
858  dimension = gmlGetProp(xnode, "srsDimension");
859  if (dimension == NULL) /* in GML 3.0.0 it was dimension */
860  dimension = gmlGetProp(xnode, "dimension");
861  if (dimension == NULL) dim = 2; /* We assume that we are in common 2D */
862  else
863  {
864  dim = atoi((char *) dimension);
865  xmlFree(dimension);
866  if (dim < 2 || dim > 3) gml_lwpgerror("invalid GML representation", 27);
867  }
868  if (dim == 2) *hasz = false;
869 
870  /* Retrieve gml:posList string */
871  gmlposlist = xmlNodeGetContent(xnode);
872  poslist = (char *) gmlposlist;
873 
874  /* HasZ?, !HasM, 1 point */
875  dpa = ptarray_construct_empty(1, 0, 1);
876 
877  /* gml:posList pattern: x1 y1 x2 y2
878  * x1 y1 z1 x2 y2 z2
879  */
880  while (isspace(*poslist)) poslist++; /* Eat extra whitespaces if any */
881  for (p=poslist, gml_dim=0, digit=false ; *poslist ; poslist++)
882  {
883  if (isdigit(*poslist)) digit = true;
884  if (digit && (*poslist == ' ' || *(poslist+1) == '\0'))
885  {
886  if (*poslist == ' ') *poslist = '\0';
887 
888  gml_dim++;
889  if (gml_dim == 1) pt.x = parse_gml_double(p, true, true);
890  else if (gml_dim == 2) pt.y = parse_gml_double(p, true, true);
891  else if (gml_dim == 3) pt.z = parse_gml_double(p, true, true);
892 
893  if (gml_dim == dim)
894  {
895  /* Add to ptarray, allowing dupes */
896  ptarray_append_point(dpa, &pt, LW_TRUE);
897  pt.x = pt.y = pt.z = pt.m = 0.0;
898  gml_dim = 0;
899  }
900  else if (*(poslist+1) == '\0')
901  gml_lwpgerror("invalid GML representation", 28);
902 
903  p = poslist+1;
904  digit = false;
905  }
906  }
907 
908  xmlFree(gmlposlist);
909 
910  return dpa; /* ptarray_clone_deep(dpa); */
911 }
912 
913 
926 static POINTARRAY* parse_gml_data(xmlNodePtr xnode, bool *hasz, int *root_srid)
927 {
928  POINTARRAY *pa = 0, *tmp_pa = 0;
929  xmlNodePtr xa, xb;
930  gmlSrs srs;
931  bool found;
932 
933  pa = NULL;
934 
935  for (xa = xnode ; xa != NULL ; xa = xa->next)
936  {
937  if (xa->type != XML_ELEMENT_NODE) continue;
938  if (!is_gml_namespace(xa, false)) continue;
939  if (xa->name == NULL) continue;
940 
941  if (is_gml_element(xa, "pos"))
942  {
943  tmp_pa = parse_gml_pos(xa, hasz);
944  if (pa == NULL) pa = tmp_pa;
945  else pa = ptarray_merge(pa, tmp_pa);
946 
947  }
948  else if (is_gml_element(xa, "posList"))
949  {
950  tmp_pa = parse_gml_poslist(xa, hasz);
951  if (pa == NULL) pa = tmp_pa;
952  else pa = ptarray_merge(pa, tmp_pa);
953 
954  }
955  else if (is_gml_element(xa, "coordinates"))
956  {
957  tmp_pa = parse_gml_coordinates(xa, hasz);
958  if (pa == NULL) pa = tmp_pa;
959  else pa = ptarray_merge(pa, tmp_pa);
960 
961  }
962  else if (is_gml_element(xa, "coord"))
963  {
964  tmp_pa = parse_gml_coord(xa, hasz);
965  if (pa == NULL) pa = tmp_pa;
966  else pa = ptarray_merge(pa, tmp_pa);
967 
968  }
969  else if (is_gml_element(xa, "pointRep") ||
970  is_gml_element(xa, "pointProperty"))
971  {
972  found = false;
973  for (xb = xa->children ; xb != NULL ; xb = xb->next)
974  {
975  if (xb->type != XML_ELEMENT_NODE) continue;
976  if (!is_gml_namespace(xb, false)) continue;
977  if (is_gml_element(xb, "Point"))
978  {
979  found = true;
980  break;
981  }
982  }
983  if (!found || xb == NULL)
984  gml_lwpgerror("invalid GML representation", 29);
985 
986  if (is_xlink(xb)) xb = get_xlink_node(xb);
987  if (xb == NULL || xb->children == NULL)
988  gml_lwpgerror("invalid GML representation", 30);
989 
990  tmp_pa = parse_gml_data(xb->children, hasz, root_srid);
991  if (tmp_pa->npoints != 1)
992  gml_lwpgerror("invalid GML representation", 31);
993 
994  parse_gml_srs(xb, &srs);
995  if (srs.reverse_axis) tmp_pa = ptarray_flip_coordinates(tmp_pa);
996  if (*root_srid == SRID_UNKNOWN) *root_srid = srs.srid;
997  else if (srs.srid != *root_srid)
998  gml_reproject_pa(tmp_pa, srs.srid, *root_srid);
999  if (pa == NULL) pa = tmp_pa;
1000  else pa = ptarray_merge(pa, tmp_pa);
1001  }
1002  }
1003 
1004  if (pa == NULL) gml_lwpgerror("invalid GML representation", 32);
1005 
1006  return pa;
1007 }
1008 
1009 
1013 static LWGEOM* parse_gml_point(xmlNodePtr xnode, bool *hasz, int *root_srid)
1014 {
1015  gmlSrs srs;
1016  LWGEOM *geom;
1017  POINTARRAY *pa;
1018 
1019  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1020  if (xnode == NULL)
1021  gml_lwpgerror("invalid GML representation", 30);
1022 
1023  if (xnode->children == NULL)
1024  return lwpoint_as_lwgeom(lwpoint_construct_empty(*root_srid, 0, 0));
1025 
1026  pa = parse_gml_data(xnode->children, hasz, root_srid);
1027  if (pa->npoints != 1) gml_lwpgerror("invalid GML representation", 34);
1028 
1029  parse_gml_srs(xnode, &srs);
1030  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
1031  if (!*root_srid)
1032  {
1033  *root_srid = srs.srid;
1034  geom = (LWGEOM *) lwpoint_construct(*root_srid, NULL, pa);
1035  }
1036  else
1037  {
1038  if (srs.srid != *root_srid)
1039  gml_reproject_pa(pa, srs.srid, *root_srid);
1040  geom = (LWGEOM *) lwpoint_construct(SRID_UNKNOWN, NULL, pa);
1041  }
1042 
1043  return geom;
1044 }
1045 
1046 
1050 static LWGEOM* parse_gml_line(xmlNodePtr xnode, bool *hasz, int *root_srid)
1051 {
1052  gmlSrs srs;
1053  LWGEOM *geom;
1054  POINTARRAY *pa;
1055 
1056  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1057  if (xnode == NULL)
1058  gml_lwpgerror("invalid GML representation", 30);
1059 
1060  if (xnode->children == NULL)
1061  return lwline_as_lwgeom(lwline_construct_empty(*root_srid, 0, 0));
1062 
1063  pa = parse_gml_data(xnode->children, hasz, root_srid);
1064  if (pa->npoints < 2) gml_lwpgerror("invalid GML representation", 36);
1065 
1066  parse_gml_srs(xnode, &srs);
1067  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
1068  if (!*root_srid)
1069  {
1070  *root_srid = srs.srid;
1071  geom = (LWGEOM *) lwline_construct(*root_srid, NULL, pa);
1072  }
1073  else
1074  {
1075  if (srs.srid != *root_srid)
1076  gml_reproject_pa(pa, srs.srid, *root_srid);
1077  geom = (LWGEOM *) lwline_construct(SRID_UNKNOWN, NULL, pa);
1078  }
1079 
1080  return geom;
1081 }
1082 
1083 
1087 static LWGEOM* parse_gml_curve(xmlNodePtr xnode, bool *hasz, int *root_srid)
1088 {
1089  xmlNodePtr xa;
1090  size_t lss;
1091  bool found=false;
1092  gmlSrs srs;
1093  LWGEOM *geom=NULL;
1094  POINTARRAY *pa=NULL;
1095  POINTARRAY **ppa=NULL;
1096  uint32 npoints=0;
1097  xmlChar *interpolation=NULL;
1098 
1099  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1100  if (xnode == NULL)
1101  gml_lwpgerror("invalid GML representation", 30);
1102 
1103  /* Looking for gml:segments */
1104  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1105  {
1106  if (xa->type != XML_ELEMENT_NODE) continue;
1107  if (!is_gml_namespace(xa, false)) continue;
1108  if (is_gml_element(xa, "segments"))
1109  {
1110  found = true;
1111  break;
1112  }
1113  }
1114  if (!found) gml_lwpgerror("invalid GML representation", 37);
1115 
1116  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1117 
1118  /* Processing each gml:LineStringSegment */
1119  for (xa = xa->children, lss=0; xa != NULL ; xa = xa->next)
1120  {
1121  if (xa->type != XML_ELEMENT_NODE) continue;
1122  if (!is_gml_namespace(xa, false)) continue;
1123 
1124  if (!is_gml_element(xa, "LineStringSegment")) continue;
1125 
1126  /* GML SF is restricted to linear interpolation */
1127  interpolation = gmlGetProp(xa, "interpolation");
1128  if (interpolation != NULL)
1129  {
1130  if (strcmp((char *) interpolation, "linear"))
1131  gml_lwpgerror("invalid GML representation", 38);
1132  xmlFree(interpolation);
1133  }
1134 
1135  if (lss > 0) ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
1136  sizeof(POINTARRAY*) * (lss + 1));
1137 
1138  ppa[lss] = parse_gml_data(xa->children, hasz, root_srid);
1139  npoints += ppa[lss]->npoints;
1140  if (ppa[lss]->npoints < 2)
1141  gml_lwpgerror("invalid GML representation", 39);
1142  lss++;
1143  }
1144  if (lss == 0) gml_lwpgerror("invalid GML representation", 40);
1145 
1146  /* Most common case, a single segment */
1147  if (lss == 1) pa = ppa[0];
1148 
1149  if (lss > 1)
1150  {
1151  /*
1152  * "The curve segments are connected to one another, with the end point
1153  * of each segment except the last being the start point of the next
1154  * segment" from ISO 19107:2003 -> 6.3.16.1 (p43)
1155  *
1156  * So we must aggregate all the segments into a single one and avoid
1157  * to copy the redundant points
1158  */
1159  size_t cp_point_size = sizeof(POINT3D); /* All internals are done with 3D */
1160  size_t final_point_size = *hasz ? sizeof(POINT3D) : sizeof(POINT2D);
1161  pa = ptarray_construct(1, 0, npoints - lss + 1);
1162 
1163  /* Copy the first linestring fully */
1164  memcpy(getPoint_internal(pa, 0), getPoint_internal(ppa[0], 0), cp_point_size * (ppa[0]->npoints));
1165  npoints = ppa[0]->npoints;
1166  lwfree(ppa[0]);
1167 
1168  /* For the rest of linestrings, ensure the first point matches the
1169  * last point of the previous one, and copy all points except the
1170  * first one (since it'd be repeated)
1171  */
1172  for (size_t i = 1; i < lss; i++)
1173  {
1174  if (memcmp(getPoint_internal(pa, npoints - 1), getPoint_internal(ppa[i], 0), final_point_size))
1175  gml_lwpgerror("invalid GML representation", 41);
1176 
1177  memcpy(getPoint_internal(pa, npoints),
1178  getPoint_internal(ppa[i], 1),
1179  cp_point_size * (ppa[i]->npoints - 1));
1180 
1181  npoints += ppa[i]->npoints - 1;
1182  lwfree(ppa[i]);
1183  }
1184  }
1185 
1186  lwfree(ppa);
1187 
1188  parse_gml_srs(xnode, &srs);
1189  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
1190  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1191  gml_reproject_pa(pa, srs.srid, *root_srid);
1192  geom = (LWGEOM *) lwline_construct(*root_srid, NULL, pa);
1193 
1194  return geom;
1195 }
1196 
1197 
1201 static LWGEOM* parse_gml_linearring(xmlNodePtr xnode, bool *hasz, int *root_srid)
1202 {
1203  gmlSrs srs;
1204  LWGEOM *geom;
1205  POINTARRAY **ppa = NULL;
1206 
1207  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1208  if (xnode == NULL)
1209  gml_lwpgerror("invalid GML representation", 30);
1210  parse_gml_srs(xnode, &srs);
1211 
1212  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1213  ppa[0] = parse_gml_data(xnode->children, hasz, root_srid);
1214 
1215  if (ppa[0]->npoints < 4
1216  || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
1217  || (*hasz && !ptarray_is_closed_3d(ppa[0])))
1218  gml_lwpgerror("invalid GML representation", 42);
1219 
1220  if (srs.reverse_axis)
1221  ppa[0] = ptarray_flip_coordinates(ppa[0]);
1222 
1223  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1224  gml_reproject_pa(ppa[0], srs.srid, *root_srid);
1225 
1226  geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, 1, ppa);
1227 
1228  return geom;
1229 }
1230 
1231 
1235 static LWGEOM* parse_gml_polygon(xmlNodePtr xnode, bool *hasz, int *root_srid)
1236 {
1237  gmlSrs srs;
1238  int i, ring;
1239  LWGEOM *geom;
1240  xmlNodePtr xa, xb;
1241  POINTARRAY **ppa = NULL;
1242 
1243  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1244  if (xnode == NULL)
1245  gml_lwpgerror("invalid GML representation", 30);
1246 
1247  if (xnode->children == NULL)
1248  return lwpoly_as_lwgeom(lwpoly_construct_empty(*root_srid, 0, 0));
1249 
1250  parse_gml_srs(xnode, &srs);
1251 
1252  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1253  {
1254  /* Polygon/outerBoundaryIs -> GML 2.1.2 */
1255  /* Polygon/exterior -> GML 3.1.1 */
1256  if (xa->type != XML_ELEMENT_NODE) continue;
1257  if (!is_gml_namespace(xa, false)) continue;
1258  if (!(is_gml_element(xa, "outerBoundaryIs") ||
1259  is_gml_element(xa, "exterior")))
1260  continue;
1261 
1262  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1263  {
1264  if (xb->type != XML_ELEMENT_NODE) continue;
1265  if (!is_gml_namespace(xb, false)) continue;
1266  if (!is_gml_element(xb, "LinearRing")) continue;
1267 
1268  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1269  ppa[0] = parse_gml_data(xb->children, hasz, root_srid);
1270 
1271  if (ppa[0]->npoints < 4
1272  || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
1273  || (*hasz && !ptarray_is_closed_3d(ppa[0])))
1274  gml_lwpgerror("invalid GML representation", 43);
1275 
1276  if (srs.reverse_axis) ppa[0] = ptarray_flip_coordinates(ppa[0]);
1277  }
1278  }
1279 
1280  /* Found an <exterior> or <outerBoundaryIs> but no rings?!? We're outa here! */
1281  if ( ! ppa )
1282  gml_lwpgerror("invalid GML representation", 43);
1283 
1284  for (ring=1, xa = xnode->children ; xa != NULL ; xa = xa->next)
1285  {
1286  /* Polygon/innerBoundaryIs -> GML 2.1.2 */
1287  /* Polygon/interior -> GML 3.1.1 */
1288  if (xa->type != XML_ELEMENT_NODE) continue;
1289  if (!is_gml_namespace(xa, false)) continue;
1290  if (!(is_gml_element(xa, "innerBoundaryIs") ||
1291  is_gml_element(xa, "interior")))
1292  continue;
1293 
1294  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1295  {
1296  if (xb->type != XML_ELEMENT_NODE) continue;
1297  if (!is_gml_namespace(xb, false)) continue;
1298  if (!is_gml_element(xb, "LinearRing")) continue;
1299 
1300  ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
1301  sizeof(POINTARRAY*) * (ring + 1));
1302  ppa[ring] = parse_gml_data(xb->children, hasz, root_srid);
1303 
1304  if (ppa[ring]->npoints < 4
1305  || (!*hasz && !ptarray_is_closed_2d(ppa[ring]))
1306  || (*hasz && !ptarray_is_closed_3d(ppa[ring])))
1307  gml_lwpgerror("invalid GML representation", 43);
1308 
1309  if (srs.reverse_axis) ppa[ring] = ptarray_flip_coordinates(ppa[ring]);
1310  ring++;
1311  }
1312  }
1313 
1314  /* Exterior Ring is mandatory */
1315  if (ppa == NULL || ppa[0] == NULL) gml_lwpgerror("invalid GML representation", 44);
1316 
1317  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1318  {
1319  for (i=0 ; i < ring ; i++)
1320  gml_reproject_pa(ppa[i], srs.srid, *root_srid);
1321  }
1322  geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, ring, ppa);
1323 
1324  return geom;
1325 }
1326 
1327 
1331 static LWGEOM* parse_gml_triangle(xmlNodePtr xnode, bool *hasz, int *root_srid)
1332 {
1333  gmlSrs srs;
1334  LWGEOM *geom;
1335  xmlNodePtr xa, xb;
1336  POINTARRAY *pa = NULL;
1337  xmlChar *interpolation=NULL;
1338 
1339  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1340  if (xnode == NULL)
1341  gml_lwpgerror("invalid GML representation", 30);
1342 
1343  if (xnode->children == NULL)
1344  return lwtriangle_as_lwgeom(lwtriangle_construct_empty(*root_srid, 0, 0));
1345 
1346  /* GML SF is restricted to planar interpolation
1347  NOTA: I know Triangle is not part of SF, but
1348  we have to be consistent with other surfaces */
1349  interpolation = gmlGetProp(xnode, "interpolation");
1350  if (interpolation != NULL)
1351  {
1352  if (strcmp((char *) interpolation, "planar"))
1353  gml_lwpgerror("invalid GML representation", 45);
1354  xmlFree(interpolation);
1355  }
1356 
1357  parse_gml_srs(xnode, &srs);
1358 
1359  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1360  {
1361  /* Triangle/exterior */
1362  if (xa->type != XML_ELEMENT_NODE) continue;
1363  if (!is_gml_namespace(xa, false)) continue;
1364  if (!is_gml_element(xa, "exterior")) continue;
1365 
1366  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1367  {
1368  /* Triangle/exterior/LinearRing */
1369  if (xb->type != XML_ELEMENT_NODE) continue;
1370  if (!is_gml_namespace(xb, false)) continue;
1371  if (!is_gml_element(xb, "LinearRing")) continue;
1372 
1373  pa = (POINTARRAY*) lwalloc(sizeof(POINTARRAY));
1374  pa = parse_gml_data(xb->children, hasz, root_srid);
1375 
1376  if (pa->npoints != 4
1377  || (!*hasz && !ptarray_is_closed_2d(pa))
1378  || (*hasz && !ptarray_is_closed_3d(pa)))
1379  gml_lwpgerror("invalid GML representation", 46);
1380 
1381  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
1382  }
1383  }
1384 
1385  /* Exterior Ring is mandatory */
1386  if (pa == NULL) gml_lwpgerror("invalid GML representation", 47);
1387 
1388  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1389  gml_reproject_pa(pa, srs.srid, *root_srid);
1390 
1391  geom = (LWGEOM *) lwtriangle_construct(*root_srid, NULL, pa);
1392 
1393  return geom;
1394 }
1395 
1396 
1400 static LWGEOM* parse_gml_patch(xmlNodePtr xnode, bool *hasz, int *root_srid)
1401 {
1402  xmlChar *interpolation=NULL;
1403  POINTARRAY **ppa=NULL;
1404  LWGEOM *geom=NULL;
1405  xmlNodePtr xa, xb;
1406  int i, ring=0;
1407  gmlSrs srs;
1408 
1409  /* PolygonPatch */
1410  if (!is_gml_element(xnode, "PolygonPatch"))
1411  gml_lwpgerror("invalid GML representation", 48);
1412 
1413  /* GML SF is restricted to planar interpolation */
1414  interpolation = gmlGetProp(xnode, "interpolation");
1415  if (interpolation != NULL)
1416  {
1417  if (strcmp((char *) interpolation, "planar"))
1418  gml_lwpgerror("invalid GML representation", 48);
1419  xmlFree(interpolation);
1420  }
1421 
1422  parse_gml_srs(xnode, &srs);
1423 
1424  /* PolygonPatch/exterior */
1425  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1426  {
1427  if (!is_gml_namespace(xa, false)) continue;
1428  if (!is_gml_element(xa, "exterior")) continue;
1429 
1430  /* PolygonPatch/exterior/LinearRing */
1431  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1432  {
1433  if (xb->type != XML_ELEMENT_NODE) continue;
1434  if (!is_gml_namespace(xb, false)) continue;
1435  if (!is_gml_element(xb, "LinearRing")) continue;
1436 
1437  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1438  ppa[0] = parse_gml_data(xb->children, hasz, root_srid);
1439 
1440  if (ppa[0]->npoints < 4
1441  || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
1442  || (*hasz && !ptarray_is_closed_3d(ppa[0])))
1443  gml_lwpgerror("invalid GML representation", 48);
1444 
1445  if (srs.reverse_axis)
1446  ppa[0] = ptarray_flip_coordinates(ppa[0]);
1447  }
1448  }
1449 
1450  /* Interior but no Exterior ! */
1451  if ( ! ppa )
1452  gml_lwpgerror("invalid GML representation", 48);
1453 
1454  /* PolygonPatch/interior */
1455  for (ring=1, xa = xnode->children ; xa != NULL ; xa = xa->next)
1456  {
1457  if (xa->type != XML_ELEMENT_NODE) continue;
1458  if (!is_gml_namespace(xa, false)) continue;
1459  if (!is_gml_element(xa, "interior")) continue;
1460 
1461  /* PolygonPatch/interior/LinearRing */
1462  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1463  {
1464  if (xb->type != XML_ELEMENT_NODE) continue;
1465  if (!is_gml_element(xb, "LinearRing")) continue;
1466 
1467  ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
1468  sizeof(POINTARRAY*) * (ring + 1));
1469  ppa[ring] = parse_gml_data(xb->children, hasz, root_srid);
1470 
1471  if (ppa[ring]->npoints < 4
1472  || (!*hasz && !ptarray_is_closed_2d(ppa[ring]))
1473  || ( *hasz && !ptarray_is_closed_3d(ppa[ring])))
1474  gml_lwpgerror("invalid GML representation", 49);
1475 
1476  if (srs.reverse_axis)
1477  ppa[ring] = ptarray_flip_coordinates(ppa[ring]);
1478 
1479  ring++;
1480  }
1481  }
1482 
1483  /* Exterior Ring is mandatory */
1484  if (ppa == NULL || ppa[0] == NULL) gml_lwpgerror("invalid GML representation", 50);
1485 
1486  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1487  {
1488  for (i=0 ; i < ring ; i++)
1489  gml_reproject_pa(ppa[i], srs.srid, *root_srid);
1490  }
1491  geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, ring, ppa);
1492 
1493  return geom;
1494 }
1495 
1496 
1500 static LWGEOM* parse_gml_surface(xmlNodePtr xnode, bool *hasz, int *root_srid)
1501 {
1502  xmlNodePtr xa;
1503  int patch;
1504  LWGEOM *geom=NULL;
1505  bool found=false;
1506 
1507  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1508  if (xnode == NULL)
1509  gml_lwpgerror("invalid GML representation", 30);
1510 
1511  /* Looking for gml:patches */
1512  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1513  {
1514  if (xa->type != XML_ELEMENT_NODE) continue;
1515  if (!is_gml_namespace(xa, false)) continue;
1516  if (is_gml_element(xa, "patches"))
1517  {
1518  found = true;
1519  break;
1520  }
1521  }
1522  if (!found) gml_lwpgerror("invalid GML representation", 51);
1523 
1524  /* Processing gml:PolygonPatch */
1525  for (patch=0, xa = xa->children ; xa != NULL ; xa = xa->next)
1526  {
1527  if (xa->type != XML_ELEMENT_NODE) continue;
1528  if (!is_gml_namespace(xa, false)) continue;
1529  if (!is_gml_element(xa, "PolygonPatch")) continue;
1530  patch++;
1531 
1532  /* SQL/MM define ST_CurvePolygon as a single patch only,
1533  cf ISO 13249-3:2009 -> 4.2.9 (p27) */
1534  if (patch > 1) gml_lwpgerror("invalid GML representation", 52);
1535 
1536  geom = parse_gml_patch(xa, hasz, root_srid);
1537  }
1538 
1539  if (!patch) gml_lwpgerror("invalid GML representation", 53);
1540 
1541  return geom;
1542 }
1543 
1544 
1554 static LWGEOM* parse_gml_tin(xmlNodePtr xnode, bool *hasz, int *root_srid)
1555 {
1556  gmlSrs srs;
1557  xmlNodePtr xa;
1558  LWGEOM *geom=NULL;
1559  bool found=false;
1560 
1561  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1562  if (xnode == NULL)
1563  gml_lwpgerror("invalid GML representation", 30);
1564 
1565  parse_gml_srs(xnode, &srs);
1566  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1567  *root_srid = srs.srid;
1568 
1569  geom = (LWGEOM *)lwcollection_construct_empty(TINTYPE, *root_srid, 1, 0);
1570 
1571  if (xnode->children == NULL)
1572  return geom;
1573 
1574  /* Looking for gml:patches or gml:trianglePatches */
1575  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1576  {
1577  if (xa->type != XML_ELEMENT_NODE) continue;
1578  if (!is_gml_namespace(xa, false)) continue;
1579  if (is_gml_element(xa, "patches") ||
1580  is_gml_element(xa, "trianglePatches"))
1581  {
1582  found = true;
1583  break;
1584  }
1585  }
1586  if (!found) return geom; /* empty one */
1587 
1588  /* Processing each gml:Triangle */
1589  for (xa = xa->children ; xa != NULL ; xa = xa->next)
1590  {
1591  if (xa->type != XML_ELEMENT_NODE) continue;
1592  if (!is_gml_namespace(xa, false)) continue;
1593  if (!is_gml_element(xa, "Triangle")) continue;
1594 
1595  if (xa->children != NULL)
1596  geom = (LWGEOM*) lwtin_add_lwtriangle((LWTIN *) geom,
1597  (LWTRIANGLE *) parse_gml_triangle(xa, hasz, root_srid));
1598  }
1599 
1600  return geom;
1601 }
1602 
1603 
1607 static LWGEOM* parse_gml_mpoint(xmlNodePtr xnode, bool *hasz, int *root_srid)
1608 {
1609  gmlSrs srs;
1610  xmlNodePtr xa, xb;
1611  LWGEOM *geom = NULL;
1612 
1613  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1614  if (xnode == NULL)
1615  gml_lwpgerror("invalid GML representation", 30);
1616 
1617  parse_gml_srs(xnode, &srs);
1618  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1619  *root_srid = srs.srid;
1620 
1621  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOINTTYPE, *root_srid, 1, 0);
1622 
1623  if (xnode->children == NULL)
1624  return geom;
1625 
1626  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1627  {
1628  /* MultiPoint/pointMember */
1629  if (xa->type != XML_ELEMENT_NODE) continue;
1630  if (!is_gml_namespace(xa, false)) continue;
1631  if (is_gml_element(xa, "pointMembers"))
1632  {
1633  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1634  {
1635  geom = (LWGEOM*)lwmpoint_add_lwpoint(
1636  (LWMPOINT*)geom,
1637  (LWPOINT*)parse_gml(xb, hasz, root_srid));
1638  }
1639  }
1640  else if (is_gml_element(xa, "pointMember"))
1641  {
1642  if (xa->children != NULL)
1643  geom = (LWGEOM*)lwmpoint_add_lwpoint((LWMPOINT*)geom,
1644  (LWPOINT*)parse_gml(xa->children, hasz, root_srid));
1645  }
1646  }
1647 
1648  return geom;
1649 }
1650 
1651 
1655 static LWGEOM* parse_gml_mline(xmlNodePtr xnode, bool *hasz, int *root_srid)
1656 {
1657  gmlSrs srs;
1658  xmlNodePtr xa;
1659  LWGEOM *geom = NULL;
1660 
1661  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1662  if (xnode == NULL)
1663  gml_lwpgerror("invalid GML representation", 30);
1664 
1665  parse_gml_srs(xnode, &srs);
1666  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1667  *root_srid = srs.srid;
1668 
1669  geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, *root_srid, 1, 0);
1670 
1671  if (xnode->children == NULL)
1672  return geom;
1673 
1674  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1675  {
1676  /* MultiLineString/lineStringMember */
1677  if (xa->type != XML_ELEMENT_NODE) continue;
1678  if (!is_gml_namespace(xa, false)) continue;
1679  if (!is_gml_element(xa, "lineStringMember")) continue;
1680  if (xa->children != NULL)
1681  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
1682  (LWLINE*)parse_gml(xa->children, hasz, root_srid));
1683  }
1684 
1685  return geom;
1686 }
1687 
1688 
1692 static LWGEOM* parse_gml_mcurve(xmlNodePtr xnode, bool *hasz, int *root_srid)
1693 {
1694  gmlSrs srs;
1695  xmlNodePtr xa, xb;
1696  LWGEOM *geom = NULL;
1697 
1698  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1699  if (xnode == NULL)
1700  gml_lwpgerror("invalid GML representation", 30);
1701 
1702  parse_gml_srs(xnode, &srs);
1703  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1704  *root_srid = srs.srid;
1705 
1706  geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, *root_srid, 1, 0);
1707 
1708  if (xnode->children == NULL)
1709  return geom;
1710 
1711  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1712  {
1713 
1714  /* MultiCurve/curveMember */
1715  if (xa->type != XML_ELEMENT_NODE) continue;
1716  if (!is_gml_namespace(xa, false)) continue;
1717  if (is_gml_element(xa, "curveMembers"))
1718  {
1719  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1720  {
1721  if (xb != NULL)
1722  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
1723  (LWLINE*)parse_gml(xb, hasz, root_srid));
1724  }
1725  }
1726  else if (is_gml_element(xa, "curveMember"))
1727  {
1728  if (xa->children != NULL)
1729  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
1730  (LWLINE*)parse_gml(xa->children, hasz, root_srid));
1731  }
1732  }
1733 
1734  return geom;
1735 }
1736 
1737 
1741 static LWGEOM* parse_gml_mpoly(xmlNodePtr xnode, bool *hasz, int *root_srid)
1742 {
1743  gmlSrs srs;
1744  xmlNodePtr xa;
1745  LWGEOM *geom = NULL;
1746 
1747  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1748  if (xnode == NULL)
1749  gml_lwpgerror("invalid GML representation", 30);
1750 
1751  parse_gml_srs(xnode, &srs);
1752  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1753  *root_srid = srs.srid;
1754 
1755  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, *root_srid, 1, 0);
1756 
1757  if (xnode->children == NULL)
1758  return geom;
1759 
1760  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1761  {
1762  /* MultiPolygon/polygonMember */
1763  if (xa->type != XML_ELEMENT_NODE) continue;
1764  if (!is_gml_namespace(xa, false)) continue;
1765  if (!is_gml_element(xa, "polygonMember")) continue;
1766  if (xa->children != NULL)
1767  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
1768  (LWPOLY*)parse_gml(xa->children, hasz, root_srid));
1769  }
1770 
1771  return geom;
1772 }
1773 
1774 
1778 static LWGEOM* parse_gml_msurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
1779 {
1780  gmlSrs srs;
1781  xmlNodePtr xa, xb;
1782  LWGEOM *geom = NULL;
1783 
1784  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1785  if (xnode == NULL)
1786  gml_lwpgerror("invalid GML representation", 30);
1787 
1788  parse_gml_srs(xnode, &srs);
1789  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1790  *root_srid = srs.srid;
1791 
1792  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, *root_srid, 1, 0);
1793 
1794  if (xnode->children == NULL)
1795  return geom;
1796 
1797  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1798  {
1799  /* MultiSurface/surfaceMember */
1800  if (xa->type != XML_ELEMENT_NODE) continue;
1801  if (!is_gml_namespace(xa, false)) continue;
1802  if (is_gml_element(xa, "surfaceMembers"))
1803  {
1804  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1805  {
1806  if (xb != NULL)
1807  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
1808  (LWPOLY*)parse_gml(xb, hasz, root_srid));
1809  }
1810  }
1811  else if (is_gml_element(xa, "surfaceMember"))
1812  {
1813  if (xa->children != NULL)
1814  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
1815  (LWPOLY*)parse_gml(xa->children, hasz, root_srid));
1816  }
1817  }
1818 
1819  return geom;
1820 }
1821 
1822 
1827 static LWGEOM* parse_gml_psurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
1828 {
1829  gmlSrs srs;
1830  xmlNodePtr xa;
1831  bool found = false;
1832  LWGEOM *geom = NULL;
1833 
1834  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1835  if (xnode == NULL)
1836  gml_lwpgerror("invalid GML representation", 30);
1837 
1838  parse_gml_srs(xnode, &srs);
1839  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1840  *root_srid = srs.srid;
1841 
1842  geom = (LWGEOM *)lwcollection_construct_empty(POLYHEDRALSURFACETYPE, *root_srid, 1, 0);
1843 
1844  if (xnode->children == NULL)
1845  return geom;
1846 
1847  /* Looking for gml:polygonPatches */
1848  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1849  {
1850  if (xa->type != XML_ELEMENT_NODE) continue;
1851  if (!is_gml_namespace(xa, false)) continue;
1852  if (is_gml_element(xa, "polygonPatches"))
1853  {
1854  found = true;
1855  break;
1856  }
1857  }
1858  if (!found) return geom;
1859 
1860  for (xa = xa->children ; xa != NULL ; xa = xa->next)
1861  {
1862  /* PolyhedralSurface/polygonPatches/PolygonPatch */
1863  if (xa->type != XML_ELEMENT_NODE) continue;
1864  if (!is_gml_namespace(xa, false)) continue;
1865  if (!is_gml_element(xa, "PolygonPatch")) continue;
1866 
1867  geom = (LWGEOM*)lwpsurface_add_lwpoly((LWPSURFACE*)geom,
1868  (LWPOLY*)parse_gml_patch(xa, hasz, root_srid));
1869  }
1870 
1871  return geom;
1872 }
1873 
1874 
1878 static LWGEOM* parse_gml_coll(xmlNodePtr xnode, bool *hasz, int *root_srid)
1879 {
1880  gmlSrs srs;
1881  xmlNodePtr xa;
1882  LWGEOM *geom = NULL;
1883 
1884  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1885  if (xnode == NULL)
1886  gml_lwpgerror("invalid GML representation", 30);
1887 
1888  parse_gml_srs(xnode, &srs);
1889  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1890  *root_srid = srs.srid;
1891 
1892  geom = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, *root_srid, 1, 0);
1893 
1894  if (xnode->children == NULL)
1895  return geom;
1896 
1897  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1898  {
1899  if (xa->type != XML_ELEMENT_NODE) continue;
1900  if (!is_gml_namespace(xa, false)) continue;
1901 
1902  /*
1903  * In GML 2.1.2 pointMember, lineStringMember and
1904  * polygonMember are parts of geometryMember
1905  * substitution group
1906  */
1907  if ( is_gml_element(xa, "pointMember")
1908  || is_gml_element(xa, "lineStringMember")
1909  || is_gml_element(xa, "polygonMember")
1910  || is_gml_element(xa, "geometryMember"))
1911  {
1912  if (xa->children == NULL) break;
1913  geom = (LWGEOM*)lwcollection_add_lwgeom((LWCOLLECTION *)geom,
1914  parse_gml(xa->children, hasz, root_srid));
1915  }
1916  }
1917 
1918  return geom;
1919 }
1920 
1924 static LWGEOM *
1925 lwgeom_from_gml(const char *xml, int xml_size)
1926 {
1927  xmlDocPtr xmldoc;
1928  xmlNodePtr xmlroot=NULL;
1929  LWGEOM *lwgeom = NULL;
1930  bool hasz=true;
1931  int root_srid=SRID_UNKNOWN;
1932 
1933  /* Begin to Parse XML doc */
1934  xmlInitParser();
1935 
1936  xmldoc = xmlReadMemory(xml, xml_size, NULL, NULL, 0);
1937  if (!xmldoc)
1938  {
1939  xmlCleanupParser();
1940  gml_lwpgerror("invalid GML representation", 1);
1941  return NULL;
1942  }
1943 
1944  xmlroot = xmlDocGetRootElement(xmldoc);
1945  if (!xmlroot)
1946  {
1947  xmlFreeDoc(xmldoc);
1948  xmlCleanupParser();
1949  gml_lwpgerror("invalid GML representation", 1);
1950  return NULL;
1951  }
1952 
1953  lwgeom = parse_gml(xmlroot, &hasz, &root_srid);
1954 
1955  xmlFreeDoc(xmldoc);
1956  xmlCleanupParser();
1957  /* shouldn't we be releasing xmldoc too here ? */
1958 
1959  if ( root_srid != SRID_UNKNOWN )
1960  lwgeom->srid = root_srid;
1961 
1962  /* GML geometries could be either 2 or 3D and can be nested mixed.
1963  * Missing Z dimension is even tolerated inside some GML coords
1964  *
1965  * So we deal with 3D in all structures allocation, and flag hasz
1966  * to false if we met once a missing Z dimension
1967  * In this case, we force recursive 2D.
1968  */
1969  if (!hasz)
1970  {
1971  LWGEOM *tmp = lwgeom_force_2d(lwgeom);
1972  lwgeom_free(lwgeom);
1973  lwgeom = tmp;
1974  }
1975 
1976  return lwgeom;
1977 }
1978 
1979 
1983 static LWGEOM* parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid)
1984 {
1985  xmlNodePtr xa = xnode;
1986  gmlSrs srs;
1987 
1988  /* Scroll forward to the root node */
1989  while (xa != NULL &&
1990  (xa->type != XML_ELEMENT_NODE || !is_gml_namespace(xa, false)))
1991  {
1992  xa = xa->next;
1993  }
1994 
1995  if (xa == NULL) gml_lwpgerror("invalid GML representation", 55);
1996 
1997  parse_gml_srs(xa, &srs);
1998  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1999  {
2000  *root_srid = srs.srid;
2001  }
2002 
2003  if (is_gml_element(xa, "Point"))
2004  return parse_gml_point(xa, hasz, root_srid);
2005 
2006  if (is_gml_element(xa, "LineString"))
2007  return parse_gml_line(xa, hasz, root_srid);
2008 
2009  if (is_gml_element(xa, "Curve"))
2010  return parse_gml_curve(xa, hasz, root_srid);
2011 
2012  if (is_gml_element(xa, "LinearRing"))
2013  return parse_gml_linearring(xa, hasz, root_srid);
2014 
2015  if (is_gml_element(xa, "Polygon"))
2016  return parse_gml_polygon(xa, hasz, root_srid);
2017 
2018  if (is_gml_element(xa, "Triangle"))
2019  return parse_gml_triangle(xa, hasz, root_srid);
2020 
2021  if (is_gml_element(xa, "Surface"))
2022  return parse_gml_surface(xa, hasz, root_srid);
2023 
2024  if (is_gml_element(xa, "MultiPoint"))
2025  return parse_gml_mpoint(xa, hasz, root_srid);
2026 
2027  if (is_gml_element(xa, "MultiLineString"))
2028  return parse_gml_mline(xa, hasz, root_srid);
2029 
2030  if (is_gml_element(xa, "MultiCurve"))
2031  return parse_gml_mcurve(xa, hasz, root_srid);
2032 
2033  if (is_gml_element(xa, "MultiPolygon"))
2034  return parse_gml_mpoly(xa, hasz, root_srid);
2035 
2036  if (is_gml_element(xa, "MultiSurface"))
2037  return parse_gml_msurface(xa, hasz, root_srid);
2038 
2039  if (is_gml_element(xa, "PolyhedralSurface"))
2040  return parse_gml_psurface(xa, hasz, root_srid);
2041 
2042  if (is_gml_element(xa, "Tin") ||
2043  is_gml_element(xa, "TriangulatedSurface"))
2044  return parse_gml_tin(xa, hasz, root_srid);
2045 
2046  if (is_gml_element(xa, "MultiGeometry"))
2047  return parse_gml_coll(xa, hasz, root_srid);
2048 
2049  gml_lwpgerror("invalid GML representation", 56);
2050  return NULL; /* Never reach */
2051 }
LWPOINT * lwpoint_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwpoint.c:151
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:339
#define LW_FALSE
Definition: liblwgeom.h:94
#define COLLECTIONTYPE
Definition: liblwgeom.h:108
int ptarray_transform(POINTARRAY *pa, LWPROJ *pj)
#define LW_FAILURE
Definition: liblwgeom.h:96
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1218
int ptarray_is_closed_3d(const POINTARRAY *pa)
Definition: ptarray.c:723
#define MULTILINETYPE
Definition: liblwgeom.h:106
LWTIN * lwtin_add_lwtriangle(LWTIN *mobj, const LWTRIANGLE *obj)
Definition: lwtin.c:34
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:329
#define MULTIPOINTTYPE
Definition: liblwgeom.h:105
LWMLINE * lwmline_add_lwline(LWMLINE *mobj, const LWLINE *obj)
Definition: lwmline.c:46
POINTARRAY * ptarray_construct(char hasz, char hasm, uint32_t npoints)
Construct an empty pointarray, allocating storage and setting the npoints, but not filling in any inf...
Definition: ptarray.c:51
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
LWTRIANGLE * lwtriangle_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwtriangle.c:58
LWMPOINT * lwmpoint_add_lwpoint(LWMPOINT *mobj, const LWPOINT *obj)
Definition: lwmpoint.c:45
#define TINTYPE
Definition: liblwgeom.h:116
LWMPOLY * lwmpoly_add_lwpoly(LWMPOLY *mobj, const LWPOLY *obj)
Definition: lwmpoly.c:47
LWPSURFACE * lwpsurface_add_lwpoly(LWPSURFACE *mobj, const LWPOLY *obj)
Definition: lwpsurface.c:33
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:107
LWPROJ * lwproj_from_str(const char *str_in, const char *str_out)
Allocate a new LWPROJ containing the reference to the PROJ's PJ If extra_geography_data is true,...
void * lwrealloc(void *mem, size_t size)
Definition: lwutil.c:242
void lwfree(void *mem)
Definition: lwutil.c:248
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:344
LWPOINT * lwpoint_construct(int32_t srid, GBOX *bbox, POINTARRAY *point)
Definition: lwpoint.c:129
#define __attribute__(x)
Definition: liblwgeom.h:228
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:114
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:59
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition: lwcollection.c:92
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE,...
Definition: ptarray.c:147
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:189
void * lwalloc(size_t size)
Definition: lwutil.c:227
int ptarray_is_closed_2d(const POINTARRAY *pa)
Definition: ptarray.c:710
LWGEOM * lwtriangle_as_lwgeom(const LWTRIANGLE *obj)
Definition: lwgeom.c:334
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:93
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:215
LWPOLY * lwpoly_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwpoly.c:161
LWPOLY * lwpoly_construct(int32_t srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
Definition: lwpoly.c:43
POINTARRAY * ptarray_merge(POINTARRAY *pa1, POINTARRAY *pa2)
Merge two given POINTARRAY and returns a pointer on the new aggregate one.
Definition: ptarray.c:612
POINTARRAY * ptarray_flip_coordinates(POINTARRAY *pa)
Reverse X and Y axis on a given POINTARRAY.
Definition: ptarray.c:368
LWLINE * lwline_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwline.c:55
LWTRIANGLE * lwtriangle_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwtriangle.c:40
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition: lwgeom.c:793
This library is the generic geometry handling section of PostGIS.
static LWGEOM * parse_gml_surface(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Surface (3.1.1)
struct struct_gmlSrs gmlSrs
static xmlNodePtr get_xlink_node(xmlNodePtr xnode)
Return a xmlNodePtr on a node referenced by a XLink or NULL otherwise.
static POINTARRAY * parse_gml_pos(xmlNodePtr xnode, bool *hasz)
Parse gml:pos.
#define GML_NS
Definition: lwgeom_in_gml.c:76
PG_FUNCTION_INFO_V1(geom_from_gml)
Ability to parse GML geometry fragment and to return an LWGEOM or an error message.
static bool is_xlink(xmlNodePtr node)
Return true if current node contains a simple XLink Return false otherwise.
#define GML32_NS
Definition: lwgeom_in_gml.c:77
#define XLINK_NS
Definition: lwgeom_in_gml.c:75
static LWGEOM * parse_gml_patch(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML PolygonPatch (3.1.1)
static LWGEOM * parse_gml_msurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiSurface (3.1.1)
static LWGEOM * parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML.
static LWGEOM * parse_gml_psurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML PolyhedralSurface (3.1.1) Nota: It's not part of SF-2.
static LWGEOM * parse_gml_coll(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiGeometry (2.1.2, 3.1.1)
static POINTARRAY * gml_reproject_pa(POINTARRAY *pa, int32_t epsg_in, int32_t epsg_out)
Use Proj to reproject a given POINTARRAY.
static double parse_gml_double(char *d, bool space_before, bool space_after)
Parse a string supposed to be a double.
static int gml_is_srs_axis_order_gis_friendly(int32_t srid)
Return 1 if the SRS definition from the authority has a GIS friendly order, that is easting,...
static LWGEOM * parse_gml_mcurve(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiCurve (3.1.1)
Datum geom_from_gml(PG_FUNCTION_ARGS)
Definition: lwgeom_in_gml.c:97
static LWGEOM * lwgeom_from_gml(const char *wkt, int xml_size)
Read GML.
static xmlChar * gmlGetProp(xmlNodePtr xnode, const char *charProp)
Retrieve a GML property from a node or NULL otherwise Respect namespaces if presents in the node elem...
static bool is_gml_namespace(xmlNodePtr xnode, bool is_strict)
Return false if current element namespace is not a GML one Return true otherwise.
static void parse_gml_srs(xmlNodePtr xnode, gmlSrs *srs)
Parse gml srsName attribute.
static LWGEOM * parse_gml_polygon(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Polygon (2.1.2, 3.1.1)
static POINTARRAY * parse_gml_coordinates(xmlNodePtr xnode, bool *hasz)
Parse gml:coordinates.
static LWGEOM * parse_gml_line(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML lineString (2.1.2, 3.1.1)
static POINTARRAY * parse_gml_data(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse data coordinates.
static LWGEOM * parse_gml_mpoly(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiPolygon (2.1.2, 3.1.1)
static POINTARRAY * parse_gml_coord(xmlNodePtr xnode, bool *hasz)
Parse gml:coord.
static LWGEOM * parse_gml_curve(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Curve (3.1.1)
static void gml_lwpgerror(char *msg, __attribute__((__unused__)) int error_code)
Definition: lwgeom_in_gml.c:81
static LWGEOM * parse_gml_mpoint(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse gml:MultiPoint (2.1.2, 3.1.1)
static LWGEOM * parse_gml_point(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML point (2.1.2, 3.1.1)
static LWGEOM * parse_gml_tin(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Tin (and TriangulatedSurface) (3.1.1)
static LWGEOM * parse_gml_triangle(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Triangle (3.1.1)
static LWGEOM * parse_gml_mline(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse gml:MultiLineString (2.1.2, 3.1.1)
static POINTARRAY * parse_gml_poslist(xmlNodePtr xnode, bool *hasz)
Parse gml:posList.
static bool is_gml_element(xmlNodePtr xn, const char *gml_name)
static LWGEOM * parse_gml_linearring(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML LinearRing (3.1.1)
void * malloc(YYSIZE_T)
void free(void *)
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition: lwinline.h:75
int value
Definition: genraster.py:62
int32_t srid
Definition: liblwgeom.h:460
PJ * pj
Definition: liblwgeom.h:46
double m
Definition: liblwgeom.h:414
double x
Definition: liblwgeom.h:414
double z
Definition: liblwgeom.h:414
double y
Definition: liblwgeom.h:414
uint32_t npoints
Definition: liblwgeom.h:427