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