PostGIS 3.7.0dev-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
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
64Datum geom_from_gml(PG_FUNCTION_ARGS);
65static LWGEOM *lwgeom_from_gml(const char *wkt, int xml_size);
66static LWGEOM* parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid);
67
68typedef 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
81static 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
97Datum 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
126static inline bool
127is_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
152static 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
197static 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
223static 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
251static 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
335static POINTARRAY *
336gml_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
378static 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
450static 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
537static 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
610static 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
726static 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
773
774 return dpa; /* ptarray_clone_deep(dpa); */
775}
776
777
781static 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
840
841 return dpa; /* ptarray_clone_deep(dpa); */
842}
843
844
848static 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
926static 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
1013static 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
1050static 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
1087static 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
1201static 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
1235static 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
1331static 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
1400static 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
1500static 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
1554static 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
1607static 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 {
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
1655static 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
1692static 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
1741static 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
1778static 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
1827static 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
1878static 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;
1914 parse_gml(xa->children, hasz, root_srid));
1915 }
1916 }
1917
1918 return geom;
1919}
1920
1924static LWGEOM *
1925lwgeom_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
1983static 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}
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition lwgeom.c:372
#define LW_FALSE
Definition liblwgeom.h:94
#define COLLECTIONTYPE
Definition liblwgeom.h:108
void * lwrealloc(void *mem, size_t size)
Definition lwutil.c:242
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:96
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1246
int ptarray_is_closed_3d(const POINTARRAY *pa)
Definition ptarray.c:723
#define MULTILINETYPE
Definition liblwgeom.h:106
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:105
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition lwgeom.c:821
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:116
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition lwline.c:42
#define MULTIPOLYGONTYPE
Definition liblwgeom.h:107
void lwfree(void *mem)
Definition lwutil.c:248
LWGEOM * lwtriangle_as_lwgeom(const LWTRIANGLE *obj)
Definition lwgeom.c:362
POINTARRAY * ptarray_merge(POINTARRAY *pa1, POINTARRAY *pa2)
Merge two given POINTARRAY and returns a pointer on the new aggregate one.
Definition ptarray.c:612
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition lwgeom.c:367
LWMLINE * lwmline_add_lwline(LWMLINE *mobj, const LWLINE *obj)
Definition lwmline.c:46
#define __attribute__(x)
Definition liblwgeom.h:228
#define POLYHEDRALSURFACETYPE
Definition liblwgeom.h:114
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:710
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:93
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:215
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:357
LWTRIANGLE * lwtriangle_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition lwtriangle.c:40
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,...
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)
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,...
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 bool is_gml_element(xmlNodePtr xn, const char *gml_name)
void * malloc(YYSIZE_T)
void free(void *)
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition lwinline.h:75
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