#!/usr/bin/env pytest
# -*- coding: utf-8 -*-
###############################################################################
# $Id: ogr_gml_geom.py 30250f784292af8d1f0ae95625b06ac482885d86 2018-12-14 10:16:24 +1300 Craig de Stigter $
#
# Project:  GDAL/OGR Test Suite
# Purpose:  Test basic OGR translation of WKT and WKB geometries.
# Author:   Frank Warmerdam <warmerdam@pobox.com>
#
###############################################################################
# Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
# Copyright (c) 2009-2014, Even Rouault <even dot rouault at mines-paris dot org>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
###############################################################################

import os

import pytest

import gdaltest
import ogrtest
from osgeo import ogr
from osgeo import osr
from osgeo import gdal

###############################################################################


@pytest.mark.parametrize(
    'filename',
    [
        f for f in os.listdir(os.path.join(os.path.dirname(__file__), 'data/wkb_wkt'))
        if f[-4:] == '.wkt'
    ]
)
def test_gml_geom(filename):
    raw_wkt = open('data/wkb_wkt/' + filename).read()

    ######################################################################
    # Convert WKT to GML.

    geom_wkt = ogr.CreateGeometryFromWkt(raw_wkt)

    gml = geom_wkt.ExportToGML()

    assert gml is not None and gml, 'Conversion to GML failed.'

    ######################################################################
    # Create geometry from GML.

    geom_gml = ogr.CreateGeometryFromGML(gml)

    if ogrtest.check_feature_geometry(geom_wkt, geom_gml, 0.0000000000001) == 1:
        clean_wkt = geom_wkt.ExportToWkt()
        gml_wkt = geom_gml.ExportToWkt()
        pytest.fail('WKT from GML (%s) does not match clean WKT (%s).\ngml was (%s)' % (gml_wkt, clean_wkt, gml))

    
###############################################################################
# Test geometries with extra spaces at the end, as sometimes are generated
# by ESRI WFS software.


def test_gml_space_test():
    gml = '<gml:LineString xmlns:foo="http://bar"><gml:coordinates xmlns:foo="http://bar" decimal="." cs="," ts=" ">189999.99995605,624999.99998375 200000.00005735,624999.99998375 200000.00005735,612499.99997125 195791.3593843,612499.99997125 193327.3749823,612499.99997125 189999.99995605,612499.99997125 189999.99995605,619462.31247125 189999.99995605,624999.99998375 \n</gml:coordinates></gml:LineString>'
    geom = ogr.CreateGeometryFromGML(gml)
    assert geom is not None and geom.GetGeometryType() is ogr.wkbLineString and geom.GetPointCount() == 8, \
        'GML not correctly parsed'

###############################################################################
# Test GML 3.x "pos" element for a point.


def test_gml_pos_point():

    gml = '<gml:Point xmlns:foo="http://bar"><gml:pos>31 29 16</gml:pos></gml:Point>'

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'POINT (31 29 16)', '<gml:pos> not correctly parsed'

###############################################################################
# Test GML 3.1.1 "pos" element for a polygon. (ticket #3244)


def test_gml_pos_polygon():

    gml = '''<gml:Polygon xmlns:foo="http://bar">
                <gml:exterior xmlns:foo="http://bar">
                    <gml:LinearRing xmlns:foo="http://bar">
                        <gml:pos xmlns:foo="http://bar">0 0</gml:pos>
                        <gml:pos>4 0</gml:pos>
                        <gml:pos>4 4</gml:pos>
                        <gml:pos>0 4</gml:pos>
                        <gml:pos>0 0</gml:pos>
                    </gml:LinearRing>
                </gml:exterior>
                <gml:interior xmlns:foo="http://bar">
                    <gml:LinearRing xmlns:foo="http://bar">
                        <gml:pos>1 1</gml:pos>
                        <gml:pos>2 1</gml:pos>
                        <gml:pos>2 2</gml:pos>
                        <gml:pos>1 2</gml:pos>
                        <gml:pos>1 1</gml:pos>
                    </gml:LinearRing>
                </gml:interior>
            </gml:Polygon>'''

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'POLYGON ((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1))', \
        '<gml:Polygon> not correctly parsed'

###############################################################################
# Test GML 3.x "posList" element for a linestring.


def test_gml_posList_line():

    gml = '<LineString xmlns:foo="http://bar"><posList xmlns:foo="http://bar">31 42 53 64 55 76</posList></LineString>'

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'LINESTRING (31 42,53 64,55 76)', \
        '<gml:posList> not correctly parsed'


###############################################################################
# Test GML 3.x "posList" element for a 3D linestring.

def test_gml_posList_line3d():

    gml = '<LineString><posList xmlns:foo="http://bar" srsDimension="3">31 42 1 53 64 2 55 76 3</posList></LineString>'

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'LINESTRING (31 42 1,53 64 2,55 76 3)', \
        '<gml:posList> not correctly parsed'

###############################################################################
# Test GML 3.x "posList" element for a 3D linestring, but with srsDimension
# set on LineString, not posList


def test_gml_posList_line3d_2():

    gml = '<LineString srsDimension="3"><posList>31 42 1 53 64 2 55 76 3</posList></LineString>'

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'LINESTRING (31 42 1,53 64 2,55 76 3)', \
        '<gml:posList> not correctly parsed'

###############################################################################
# Test GML 3.x "polygon" element for a point.


def test_gml_polygon():

    gml = '<Polygon><exterior><LinearRing><posList>0 0 4 0 4 4 0 4 0 0</posList></LinearRing></exterior><interior xmlns:foo="http://bar"><LinearRing><posList xmlns:foo="http://bar">1 1 2 1 2 2 1 2 1 1</posList></LinearRing></interior></Polygon>'
    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'POLYGON ((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1))', \
        '<gml:Polygon> not correctly parsed'

###############################################################################
# Private utility function to convert WKT to GML with assigned WGS 84 as SRS.


def _CreateGMLWithSRSFromWkt(wkt, epsg):

    geom = ogr.CreateGeometryFromWkt(wkt)

    if geom is None:
        gdaltest.post_reason('Import geometry from WKT failed')
        return None

    # Assign SRS from given EPSG code
    srs = osr.SpatialReference()
    srs.ImportFromEPSG(epsg)

    if srs is None:
        gdaltest.post_reason('SRS import from EPSG failed')
        return None

    geom.AssignSpatialReference(srs)

    return geom.ExportToGML()

###############################################################################
# Test of Point geometry with SRS assigned


def test_gml_out_point_srs():

    wkt = 'POINT(21.675 53.763)'

    gml = _CreateGMLWithSRSFromWkt(wkt, 4326)

    assert gml is not None and gml, 'Conversion to GML failed.'

    assert gml[0:31] == '<gml:Point srsName="EPSG:4326">', \
        'No srsName attribute in GML output'

###############################################################################
# Test of Point 3D geometry with SRS assigned


def test_gml_out_point3d_srs():

    wkt = 'POINT(21.675 53.763 100)'

    gml = _CreateGMLWithSRSFromWkt(wkt, 4326)

    assert gml is not None and gml, 'Conversion to GML failed.'

    assert gml[0:31] == '<gml:Point srsName="EPSG:4326">', \
        'No srsName attribute in GML output'

###############################################################################
# Test of LineString geometry with SRS assigned


def test_gml_out_linestring_srs():

    wkt = open('data/wkb_wkt/5.wkt').read()

    gml = _CreateGMLWithSRSFromWkt(wkt, 4326)

    assert gml is not None and gml, 'Conversion to GML failed.'

    assert gml[0:36] == '<gml:LineString srsName="EPSG:4326">', \
        'No srsName attribute in GML output'

###############################################################################
# Test of Polygon geometry with SRS assigned


def test_gml_out_polygon_srs():

    wkt = open('data/wkb_wkt/6.wkt').read()

    gml = _CreateGMLWithSRSFromWkt(wkt, 4326)

    assert gml is not None and gml, 'Conversion to GML failed.'

    assert gml[0:33] == '<gml:Polygon srsName="EPSG:4326">', \
        'No srsName attribute in GML output'

###############################################################################
# Test of MultiPoint geometry with SRS assigned


def test_gml_out_multipoint_srs():

    wkt = open('data/wkb_wkt/11.wkt').read()

    gml = _CreateGMLWithSRSFromWkt(wkt, 4326)

    assert gml is not None and gml, 'Conversion to GML failed.'

    assert gml[0:36] == '<gml:MultiPoint srsName="EPSG:4326">', \
        'No srsName attribute in GML output'

###############################################################################
# Test of MultiLineString geometry with SRS assigned


def test_gml_out_multilinestring_srs():

    wkt = open('data/wkb_wkt/2.wkt').read()

    gml = _CreateGMLWithSRSFromWkt(wkt, 4326)

    assert gml is not None and gml, 'Conversion to GML failed.'

    assert gml[0:41] == '<gml:MultiLineString srsName="EPSG:4326">', \
        'No srsName attribute in GML output'

###############################################################################
# Test of MultiPolygon geometry with SRS assigned


def test_gml_out_multipolygon_srs():

    wkt = open('data/wkb_wkt/4.wkt').read()

    gml = _CreateGMLWithSRSFromWkt(wkt, 4326)

    assert gml is not None and gml, 'Conversion to GML failed.'

    assert gml[0:38] == '<gml:MultiPolygon srsName="EPSG:4326">', \
        'No srsName attribute in GML output'

    # Verify we have no other srsName's on subelements.
    assert gml[39:].find('srsName') == -1, \
        'Got extra srsName attributes on subelements.'

###############################################################################
# Test of GeometryCollection with SRS assigned


def test_gml_out_geometrycollection_srs():

    wkt = open('data/wkb_wkt/3.wkt').read()

    gml = _CreateGMLWithSRSFromWkt(wkt, 4326)

    assert gml is not None and gml, 'Conversion to GML failed.'

    assert gml[0:39] == '<gml:MultiGeometry srsName="EPSG:4326">', \
        'No srsName attribute in GML output'

###############################################################################
# Test GML Box


def test_gml_Box():

    gml = """<gml:Box xmlns:gml="http://www.opengis.net/gml" srsName="foo">
  <gml:coord>
    <gml:X>1</gml:X>
    <gml:Y>2</gml:Y>
  </gml:coord>
  <gml:coord>
    <gml:X>3</gml:X>
    <gml:Y>4</gml:Y>
  </gml:coord>
</gml:Box>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'POLYGON ((1 2 0,3 2 0,3 4 0,1 4 0,1 2 0))', \
        '<gml:Box> not correctly parsed'

###############################################################################
# Test GML Envelope


def test_gml_Envelope():

    gml = """<gml:Envelope xmlns:gml="http://www.opengis.net/gml" srsName="foo">
    <gml:lowerCorner>1 2</gml:lowerCorner>
    <gml:upperCorner>3 4</gml:upperCorner>
</gml:Envelope>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'POLYGON ((1 2,3 2,3 4,1 4,1 2))', \
        '<gml:Envelope> not correctly parsed'

###############################################################################
# Test GML Curve


def test_gml_Curve():

    gml = """<gml:Curve xmlns:gml="http://www.opengis.net/gml" srsName="foo">
    <gml:segments xmlns:foo="http://bar">
        <gml:LineStringSegment xmlns:foo="http://bar">
            <gml:posList>1 2 3 4</gml:posList>
        </gml:LineStringSegment>
    </gml:segments>
</gml:Curve>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'LINESTRING (1 2,3 4)', \
        '<gml:Curve> not correctly parsed'

###############################################################################
# Test GML Curve with pointProperty elements


def test_gml_Curve_with_pointProperty():

    gml = """<gml:Curve xmlns:gml="http://www.opengis.net/gml" srsName="foo">
    <gml:segments>
        <gml:LineStringSegment>
            <gml:pos>1 2</gml:pos>
            <gml:pointProperty>
                <gml:Point>
                    <gml:pos>3 4</gml:pos>
                </gml:Point>
            </gml:pointProperty>
        </gml:LineStringSegment>
    </gml:segments>
</gml:Curve>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'LINESTRING (1 2,3 4)', \
        '<gml:Curve> not correctly parsed'

###############################################################################
# Test GML MultiCurve


def test_gml_MultiCurve():

    gml = """<gml:MultiCurve xmlns:foo="http://bar" xmlns:gml="http://www.opengis.net/gml" srsName="foo">
    <gml:curveMember xmlns:foo="http://bar">
        <gml:LineString>
            <gml:posList>1 2 2 3</gml:posList>
        </gml:LineString>
    </gml:curveMember>
    <gml:curveMember>
        <gml:LineString>
            <gml:posList>3 4 4 5</gml:posList>
        </gml:LineString>
    </gml:curveMember>
</gml:MultiCurve>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'MULTILINESTRING ((1 2,2 3),(3 4,4 5))', \
        '<gml:MultiCurve> not correctly parsed'

###############################################################################
# Test GML MultiSurface with PolygonPatch


def test_gml_MultiSurface():

    gml = """<gml:MultiSurface xmlns:gml="http://www.opengis.net/gml" srsName="foo">
    <gml:surfaceMember xmlns:foo="http://bar" xlink:role="main">
        <gml:Surface gml:id="id1">
            <gml:patches xmlns:foo="http://bar">
                <gml:PolygonPatch xmlns:foo="http://bar" interpolation="planar">
                    <gml:exterior>
                        <gml:LinearRing>
                            <gml:posList>1 2 3 4 5 6 1 2</gml:posList>
                        </gml:LinearRing>
                    </gml:exterior>
                    <gml:interior>
                        <gml:LinearRing>
                            <gml:posList>2 3 4 5 6 7 2 3</gml:posList>
                        </gml:LinearRing>
                    </gml:interior>
                    <gml:interior>
                        <gml:LinearRing>
                            <gml:posList>3 4 5 6 7 8 3 4</gml:posList>
                        </gml:LinearRing>
                    </gml:interior>
                </gml:PolygonPatch>
            </gml:patches>
        </gml:Surface>
    </gml:surfaceMember>
    <gml:surfaceMember>
        <gml:Surface>
            <gml:patches>
                <gml:PolygonPatch interpolation="planar">
                    <gml:exterior>
                        <gml:Ring>
                            <gml:curveMember>
                                <gml:Curve>
                                    <gml:segments>
                                        <gml:LineStringSegment>
                                            <gml:pos>4 5</gml:pos>
                                            <gml:pos>6 7</gml:pos>
                                        </gml:LineStringSegment>
                                    </gml:segments>
                                </gml:Curve>
                            </gml:curveMember>
                            <gml:curveMember>
                                <gml:Curve>
                                    <gml:segments>
                                        <gml:LineStringSegment>
                                            <gml:pos>6 7</gml:pos>
                                            <gml:pos>8 9</gml:pos>
                                        </gml:LineStringSegment>
                                    </gml:segments>
                                </gml:Curve>
                            </gml:curveMember>
                            <gml:curveMember>
                                <gml:Curve>
                                    <gml:segments>
                                        <gml:LineStringSegment>
                                            <gml:pos>8 9</gml:pos>
                                            <gml:pos>4 5</gml:pos>
                                        </gml:LineStringSegment>
                                    </gml:segments>
                                </gml:Curve>
                            </gml:curveMember>
                        </gml:Ring>
                    </gml:exterior>
                </gml:PolygonPatch>
            </gml:patches>
        </gml:Surface>
    </gml:surfaceMember>
</gml:MultiSurface>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'MULTIPOLYGON (((1 2,3 4,5 6,1 2),(2 3,4 5,6 7,2 3),(3 4,5 6,7 8,3 4)),((4 5,6 7,8 9,4 5)))', \
        '<gml:MultiSurface> not correctly parsed'


###############################################################################
# Test GML MultiSurface with surfaceMembers

def test_gml_MultiSurface_surfaceMembers():

    gml = """<gml:MultiSurface xmlns:foo="http://bar">
          <gml:surfaceMembers xmlns:foo="http://bar">
            <gml:Surface xmlns:foo="http://bar">
              <gml:patches xmlns:foo="http://bar">
                <gml:PolygonPatch xmlns:foo="http://bar">
                  <gml:exterior xmlns:foo="http://bar">
                      <gml:LinearRing xmlns:foo="http://bar">
                          <gml:posList>1 2 3 4 5 6 1 2</gml:posList>
                      </gml:LinearRing>
                    </gml:exterior>
                    <gml:interior>
                      <gml:LinearRing>
                          <gml:posList>2 3 4 5 6 7 2 3</gml:posList>
                      </gml:LinearRing>
                    </gml:interior>
                </gml:PolygonPatch>
              </gml:patches>
            </gml:Surface>
            <gml:Surface>
              <gml:patches>
                <gml:PolygonPatch>
                  <gml:exterior>
                    <gml:LinearRing>
                      <gml:posList>3 4 5 6 7 8 3 4</gml:posList>
                    </gml:LinearRing>
                  </gml:exterior>
                </gml:PolygonPatch>
                <gml:PolygonPatch>
                  <gml:exterior>
                    <gml:LinearRing>
                      <gml:posList>30 40 50 60 70 80 30 40</gml:posList>
                    </gml:LinearRing>
                  </gml:exterior>
                </gml:PolygonPatch>
              </gml:patches>
            </gml:Surface>
          </gml:surfaceMembers>
        </gml:MultiSurface>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'MULTIPOLYGON (((1 2,3 4,5 6,1 2),(2 3,4 5,6 7,2 3)),((3 4,5 6,7 8,3 4)),((30 40,50 60,70 80,30 40)))', \
        '<gml:MultiSurface> not correctly parsed'


###############################################################################
# Test GML MultiCurve with curveMembers

def test_gml_MultiCurve_curveMembers():

    gml = """<gml:MultiCurve xmlns:foo="http://bar">
          <gml:curveMembers xmlns:foo="http://bar">
            <gml:LineString xmlns:foo="http://bar">
                <gml:posList xmlns:foo="http://bar" srsDimension="2">0 0 1 1</gml:posList>
              </gml:LineString>
            </gml:curveMembers>
          </gml:MultiCurve>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'MULTILINESTRING ((0 0,1 1))', \
        '<gml:MultiCurve> not correctly parsed'

###############################################################################
# Test GML MultiGeometry with geometryMembers

def test_gml_MultiGeometry_geometryMembers():

    gml = """<gml:MultiGeometry xmlns:foo="http://bar">
          <gml:geometryMembers xmlns:foo="http://bar">
            <gml:LineString xmlns:foo="http://bar">
                <gml:posList xmlns:foo="http://bar" srsDimension="2">0 0 1 1</gml:posList>
              </gml:LineString>
            </gml:geometryMembers>
          </gml:MultiGeometry>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'GEOMETRYCOLLECTION (LINESTRING (0 0,1 1))', \
        '<gml:MultiGeometry> not correctly parsed'

###############################################################################
# Test GML CompositeCurve with curveMembers


def test_gml_CompositeCurve_curveMembers():

    gml = """<gml:CompositeCurve xmlns:foo="http://bar">
          <gml:curveMembers xmlns:foo="http://bar">
            <gml:LineString xmlns:foo="http://bar">
                <gml:posList xmlns:foo="http://bar" srsDimension="2">0 0 1 1</gml:posList>
            </gml:LineString>
            <gml:LineString xmlns:foo="http://bar">
                <gml:posList xmlns:foo="http://bar" srsDimension="2">1 1 2 2</gml:posList>
            </gml:LineString>
          </gml:curveMembers>
        </gml:CompositeCurve>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'LINESTRING (0 0,1 1,2 2)', \
        '<gml:CompositeCurve> not correctly parsed'

###############################################################################
# Test GML MultiPoint with pointMembers


def test_gml_MultiCurve_pointMembers():

    gml = """<gml:MultiPoint xmlns:foo="http://bar">
          <gml:pointMembers xmlns:foo="http://bar">
              <gml:Point xmlns:foo="http://bar">
                <gml:pos xmlns:foo="http://bar">0 0</gml:pos>
              </gml:Point>
              <gml:Point>
                <gml:pos>1 1</gml:pos>
              </gml:Point>
            </gml:pointMembers>
          </gml:MultiPoint>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'MULTIPOINT (0 0,1 1)', \
        '<gml:MultiPoint> not correctly parsed'
###############################################################################
# Test GML Solid


def test_gml_Solid():

    gml = """<gml:Solid xmlns:foo="http://bar" gml:id="UUID_cc5a9513-2d85-4f1a-869a-620400182e1f">
          <gml:exterior xmlns:foo="http://bar">
            <gml:CompositeSurface xmlns:foo="http://bar" gml:id="UUID_2c83341e-a9ce-4abe-9c40-b5208eed5588">
              <gml:surfaceMember xmlns:foo="http://bar">
                <gml:Polygon xmlns:foo="http://bar" gml:id="UUID_d8e4b04b-ce0a-441e-b940-5ab99fcf6112">
                  <gml:exterior xmlns:foo="http://bar">
                    <gml:LinearRing xmlns:foo="http://bar" gml:id="UUID_d8e4b04b-ce0a-441e-b940-5ab99fcf6112_0">
                      <gml:posList xmlns:foo="http://bar">1 2 0 3 4 0 5 6 0 1 2 0</gml:posList>
                    </gml:LinearRing>
                  </gml:exterior>
                </gml:Polygon>
              </gml:surfaceMember>
            </gml:CompositeSurface>
          </gml:exterior>
        </gml:Solid>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'POLYHEDRALSURFACE Z (((1 2 0,3 4 0,5 6 0,1 2 0)))', \
        '<gml:Solid> not correctly parsed'

###############################################################################
# Test GML OrientableSurface


def test_gml_OrientableSurface():

    gml = """<gml:OrientableSurface xmlns:foo="http://bar" orientation="+">
                                            <gml:baseSurface xmlns:foo="http://bar">
                                                <gml:Polygon>
                                                  <gml:exterior>
                                                  <gml:LinearRing>
                                                  <gml:posList srsDimension="3">-213.475 24.989 0
                                                  -213.475 24.989 8.0 -215.704 25.077 8.0 -215.704
                                                  25.077 0 -213.475 24.989 0 </gml:posList>
                                                  </gml:LinearRing>
                                                  </gml:exterior>
                                                </gml:Polygon>
                                            </gml:baseSurface>
                                        </gml:OrientableSurface>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'POLYGON ((-213.475 24.989 0,-213.475 24.989 8,-215.704 25.077 8,-215.704 25.077 0,-213.475 24.989 0))', \
        '<gml:OrientableSurface> not correctly parsed'

###############################################################################
# Test GML Triangle


def test_gml_Triangle():

    gml = """<gml:Triangle xmlns:foo="http://bar">
                <gml:exterior>
                    <gml:LinearRing>
                        <gml:posList>0 0 0 1 1 1 0 0</gml:posList>
                     </gml:LinearRing>
                </gml:exterior>
             </gml:Triangle>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'TRIANGLE ((0 0,0 1,1 1,0 0))', \
        '<gml:Triangle> not correctly parsed'

    # check the conversion of Triangle from OGR -> GML
    wkt_original = 'TRIANGLE ((0 0,0 1,0 1,0 0))'
    triangle = ogr.CreateGeometryFromWkt(wkt_original)
    opts = ["FORMAT=GML3"]
    gml_string = triangle.ExportToGML(opts)

    if gml_string != '<gml:Triangle><gml:exterior><gml:LinearRing><gml:posList>0 0 0 1 0 1 0 0</gml:posList></gml:LinearRing></gml:exterior></gml:Triangle>':
        print(geom.ExportToWkt())
        pytest.fail('incorrect conversion from OGR -> GML for OGRTriangle')

    
###############################################################################
# Test GML Rectangle


def test_gml_Rectangle():

    gml = """<gml:Rectangle xmlns:foo="http://bar">
                <gml:exterior>
                    <gml:LinearRing>
                        <gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
                     </gml:LinearRing>
                </gml:exterior>
             </gml:Rectangle>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'POLYGON ((0 0,0 1,1 1,1 0,0 0))', \
        '<gml:Rectangle> not correctly parsed'

###############################################################################
# Test GML PolyhedralSurface


def test_gml_PolyhedralSurface():

    # Conversion from GML -> OGR

    # 2 patches and 2 rings
    gml = """<gml:PolyhedralSurface>
                <gml:polygonPatches>
                    <gml:PolygonPatch>
                        <gml:exterior>
                            <gml:LinearRing>
                                <gml:posList srsDimension="3">1 2 3 4 5 6 7 8 9 1 2 3</gml:posList>
                            </gml:LinearRing>
                        </gml:exterior>
                    </gml:PolygonPatch>
                    <gml:PolygonPatch>
                        <gml:exterior>
                            <gml:LinearRing>
                                <gml:posList srsDimension="3">10 11 12 13 14 15 16 17 18 10 11 12</gml:posList>
                            </gml:LinearRing>
                        </gml:exterior>
                        <gml:interior>
                            <gml:LinearRing>
                                <gml:posList srsDimension="3">19 20 21 22 23 24 25 26 27 19 20 21</gml:posList>
                            </gml:LinearRing>
                        </gml:interior>
                    </gml:PolygonPatch>
                </gml:polygonPatches>
            </gml:PolyhedralSurface>"""
    geom = ogr.CreateGeometryFromGML(gml)

    # NOTE - this is actually an invalid PolyhedralSurface
    # need to assert geom.IsValid() == True to determine the validity of the geometry
    assert geom.ExportToWkt() == 'POLYHEDRALSURFACE Z (((1 2 3,4 5 6,7 8 9,1 2 3)),((10 11 12,13 14 15,16 17 18,10 11 12),(19 20 21,22 23 24,25 26 27,19 20 21)))', \
        '<gml:PolyhedralSurface> not correctly parsed'

    # 1 patch and 2 rings
    gml = """<gml:PolyhedralSurface>
                <gml:polygonPatches>
                    <gml:PolygonPatch>
                        <gml:exterior>
                            <gml:LinearRing>
                                <gml:posList srsDimension="3">1 2 3 4 5 6 7 8 9 1 2 3</gml:posList>
                            </gml:LinearRing></gml:exterior>
                        </gml:PolygonPatch>
                    <gml:PolygonPatch>
                        <gml:exterior>
                            <gml:LinearRing>
                                <gml:posList srsDimension="3">10 11 12 13 14 15 16 17 18 10 11 12</gml:posList>
                            </gml:LinearRing>
                        </gml:exterior>
                    </gml:PolygonPatch>
            </gml:polygonPatches>
            </gml:PolyhedralSurface>"""

    geom = ogr.CreateGeometryFromGML(gml)

    # NOTE - this is actually an invalid PolyhedralSurface
    # need to assert geom.IsValid() == True to determine the validity of the geometry
    assert geom.ExportToWkt() == 'POLYHEDRALSURFACE Z (((1 2 3,4 5 6,7 8 9,1 2 3)),((10 11 12,13 14 15,16 17 18,10 11 12)))', \
        '<gml:PolyhedralSurface> not correctly parsed'

    # Variations of empty PolyhedralSurface
    gml_strings = ['<gml:PolyhedralSurface></gml:PolyhedralSurface>',
                   '<gml:PolyhedralSurface><gml:polygonPatches></gml:polygonPatches></gml:PolyhedralSurface>',
                   """<gml:PolyhedralSurface>
                           <gml:polygonPatches>
                               <gml:PolygonPatch>
                                   <gml:exterior>
                                   </gml:exterior>
                               </gml:PolygonPatch>
                           </gml:polygonPatches>
                       </gml:PolyhedralSurface>"""]

    for string in gml_strings:
        geom = ogr.CreateGeometryFromGML(string)
        assert geom.ExportToWkt() == 'POLYHEDRALSURFACE EMPTY', \
            'Empty <gml:PolyhedralSurface> not correctly parsed'

    # Conversion from OGR -> GML
    wkt_original = 'POLYHEDRALSURFACE Z (((0 0 0,0 0 1,0 1 1,0 1 0,0 0 0)),\
((0 0 0,0 1 0,1 1 0,1 0 0,0 0 0)),\
((0 0 0,1 0 0,1 0 1,0 0 1,0 0 0)),\
((1 1 0,1 1 1,1 0 1,1 0 0,1 1 0)),\
((0 1 0,0 1 1,1 1 1,1 1 0,0 1 0)),\
((0 0 1,1 0 1,1 1 1,0 1 1,0 0 1)))'
    ps = ogr.CreateGeometryFromWkt(wkt_original)
    opts = ["FORMAT=GML3"]
    string = ps.ExportToGML(opts)
    if string != '<gml:PolyhedralSurface><gml:polygonPatches><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:posList srsDimension="3">0 0 0 0 0 1 0 1 1 0 1 0 0 0 0</gml:posList></gml:LinearRing></gml:exterior></gml:PolygonPatch><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:posList srsDimension="3">0 0 0 0 1 0 1 1 0 1 0 0 0 0 0</gml:posList></gml:LinearRing></gml:exterior></gml:PolygonPatch><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:posList srsDimension="3">0 0 0 1 0 0 1 0 1 0 0 1 0 0 0</gml:posList></gml:LinearRing></gml:exterior></gml:PolygonPatch><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:posList srsDimension="3">1 1 0 1 1 1 1 0 1 1 0 0 1 1 0</gml:posList></gml:LinearRing></gml:exterior></gml:PolygonPatch><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:posList srsDimension="3">0 1 0 0 1 1 1 1 1 1 1 0 0 1 0</gml:posList></gml:LinearRing></gml:exterior></gml:PolygonPatch><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:posList srsDimension="3">0 0 1 1 0 1 1 1 1 0 1 1 0 0 1</gml:posList></gml:LinearRing></gml:exterior></gml:PolygonPatch></gml:polygonPatches></gml:PolyhedralSurface>':
        print(geom.ExportToWkt())
        pytest.fail('incorrect parsing of OGR -> GML for PolyhedralSurface')

    g2 = ogr.CreateGeometryFromGML(string)
    if g2.Equals(ps) != 1:
        print(geom.ExportToWkt())
        pytest.fail('incorrect round-tripping')

    # empty geometry
    wkt_original = 'POLYHEDRALSURFACE EMPTY'
    ps = ogr.CreateGeometryFromWkt(wkt_original)
    opts = ["FORMAT=GML3"]
    string = ps.ExportToGML(opts)
    if string != '<gml:PolyhedralSurface><gml:polygonPatches></gml:polygonPatches></gml:PolyhedralSurface>':
        print(geom.ExportToWkt())
        pytest.fail('incorrect parsing of OGR -> GML for empty PolyhedralSurface')

    # several polygon patches (and test that non elements such as comments are parsed OK)
    gml = """<gml:PolyhedralSurface>
                <gml:polygonPatches>
                    <gml:PolygonPatch>
                        <gml:exterior>
                            <gml:LinearRing>
                                <gml:posList srsDimension="3">1 2 3 4 5 6 7 8 9 1 2 3</gml:posList>
                            </gml:LinearRing>
                        </gml:exterior>
                    </gml:PolygonPatch>
                    <!--- --->
                </gml:polygonPatches>
                <!--- --->
                <gml:polygonPatches>
                    <gml:PolygonPatch>
                        <gml:exterior>
                            <gml:LinearRing>
                                <gml:posList srsDimension="3">1 2 3 4 5 6 7 8 9 1 2 3</gml:posList>
                            </gml:LinearRing>
                        </gml:exterior>
                    </gml:PolygonPatch>
                </gml:polygonPatches>
            </gml:PolyhedralSurface>"""

    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'GEOMETRYCOLLECTION (POLYHEDRALSURFACE (((1 2 3,4 5 6,7 8 9,1 2 3))),POLYHEDRALSURFACE (((1 2 3,4 5 6,7 8 9,1 2 3))))', \
        '<gml:PolyhedralSurface> not correctly parsed'

    # Test PolyhedralSurface with curve section (which we linearize since the SF PolyhedralSurface doesn't support curves)
    gml = """<gml:PolyhedralSurface>
                <gml:polygonPatches>
                    <gml:PolygonPatch interpolation="planar">
                        <gml:exterior>
                            <gml:Ring>
                                <gml:curveMember>
                                    <gml:Curve>
                                        <gml:segments>
                                            <gml:LineStringSegment interpolation="linear">
                                                <gml:pos>0 -1</gml:pos>
                                                <gml:pos>0 1</gml:pos>
                                            </gml:LineStringSegment>
                                            <gml:Arc interpolation="circularArc3Points" numArc="1">
                                                <gml:pos>0 1</gml:pos>
                                                <gml:pos>1 0</gml:pos>
                                                <gml:pos>0 -1</gml:pos>
                                            </gml:Arc>
                                        </gml:segments>
                                    </gml:Curve>
                                </gml:curveMember>
                            </gml:Ring>
                        </gml:exterior>
                    </gml:PolygonPatch>
                </gml:polygonPatches>
            </gml:PolyhedralSurface>"""

    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt().find('POLYHEDRALSURFACE (((0 -1,0 1,') >= 0, \
        '<gml:PolyhedralSurface> not correctly parsed'


###############################################################################
# Test GML Tin

def test_gml_Tin():

    gml = """<gml:Tin xmlns:foo="http://bar">
                <gml:patches xmlns:foo="http://bar">
                    <gml:Triangle xmlns:foo="http://bar">
                        <gml:exterior xmlns:foo="http://bar">
                            <gml:LinearRing xmlns:foo="http://bar">
                                <gml:posList srsDimension="3">0 0 1 0 1 1 1 1 1 1 0 1 0 0 1 </gml:posList>
                            </gml:LinearRing>
                        </gml:exterior>
                     </gml:Triangle>
                 </gml:patches>
             </gml:Tin>"""

    geom = ogr.CreateGeometryFromGML(gml)

    # NOTE - this is actually an invalid TIN surface, as the triangle is incorrect
    # need to assert geom.IsValid() == True to determine the validity of the geometry
    assert geom.ExportToWkt() == 'TIN Z (((0 0 1,0 1 1,1 1 1,1 0 1,0 0 1)))', \
        '<gml:Tin> not correctly parsed'

    # Test for gml:TriangulatedSurface
    gml = """<gml:TriangulatedSurface>
                <gml:patches>
                    <gml:Triangle>
                        <gml:exterior>
                            <gml:LinearRing>
                                <gml:posList srsDimension="3">0 0 0 0 0 1 0 1 0 0 0 0</gml:posList>
                            </gml:LinearRing>
                        </gml:exterior>
                    </gml:Triangle>
                    <gml:Triangle>
                        <gml:exterior>
                            <gml:LinearRing>
                                <gml:posList srsDimension="3">0 0 0 0 1 0 1 1 0 0 0 0</gml:posList>
                            </gml:LinearRing>
                        </gml:exterior>
                    </gml:Triangle>
                </gml:patches>
            </gml:TriangulatedSurface>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'TIN Z (((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 1 0,0 0 0)))', \
        '<gml:Tin> not correctly parsed'

    # substituting gml:trianglePatches for gml:patches
    gml = """<gml:TriangulatedSurface>
                <gml:trianglePatches>
                    <gml:Triangle>
                        <gml:exterior>
                            <gml:LinearRing>
                                <gml:posList srsDimension="3">0 0 0 0 0 1 0 1 0 0 0 0</gml:posList>
                            </gml:LinearRing>
                        </gml:exterior>
                    </gml:Triangle>
                    <gml:Triangle>
                        <gml:exterior>
                            <gml:LinearRing>
                                <gml:posList srsDimension="3">0 0 0 0 1 0 1 1 0 0 0 0</gml:posList>
                            </gml:LinearRing>
                        </gml:exterior>
                    </gml:Triangle>
                </gml:trianglePatches>
            </gml:TriangulatedSurface>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'TIN Z (((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 1 0,0 0 0)))', \
        '<gml:Tin> not correctly parsed'

    # Part 2 - Create GML File from OGR Geometries
    wkt_original = 'TIN Z (((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 1 0,0 0 0)))'

    tin = ogr.CreateGeometryFromWkt(wkt_original)
    opts = ["FORMAT=GML3"]
    gml_string = tin.ExportToGML(opts)

    if gml_string != '<gml:TriangulatedSurface><gml:patches><gml:Triangle><gml:exterior><gml:LinearRing><gml:posList srsDimension="3">0 0 0 0 0 1 0 1 0 0 0 0</gml:posList></gml:LinearRing></gml:exterior></gml:Triangle><gml:Triangle><gml:exterior><gml:LinearRing><gml:posList srsDimension="3">0 0 0 0 1 0 1 1 0 0 0 0</gml:posList></gml:LinearRing></gml:exterior></gml:Triangle></gml:patches></gml:TriangulatedSurface>':
        print(geom.ExportToWkt())
        pytest.fail('OGRGeometry::TriangulatedSurface incorrectly converted')

    
###############################################################################
# Test concatenated sections (#4451)


def test_gml_ConcatenatedDeduplication():

    gml = """<gml:Surface>
       <gml:patches>
        <gml:PolygonPatch interpolation="planar">
         <gml:exterior>
          <gml:Ring>
           <gml:curveMember>
            <gml:Curve>
             <gml:segments>
              <gml:LineStringSegment interpolation="linear">
               <gml:pos>0 -1</gml:pos>
               <gml:pos>0 1</gml:pos>
              </gml:LineStringSegment>
              <gml:Arc interpolation="circularArc3Points" numArc="1">
               <gml:pos>0 1</gml:pos>
               <gml:pos>1 0</gml:pos>
               <gml:pos>0 -1</gml:pos>
              </gml:Arc>
             </gml:segments>
            </gml:Curve>
           </gml:curveMember>
          </gml:Ring></gml:exterior>
         </gml:PolygonPatch>
        </gml:patches>
       </gml:Surface>"""

    geom = ogr.CreateGeometryFromGML(gml)

    expected_wkt = 'CURVEPOLYGON (COMPOUNDCURVE ((0 -1,0 1),CIRCULARSTRING (0 1,1 0,0 -1)))'
    assert ogrtest.check_feature_geometry(geom, ogr.CreateGeometryFromWkt(expected_wkt)) == 0

    assert not ogrtest.have_geos() or geom.IsValid(), 'geometry not valid'

###############################################################################
# Test OGRFormatDouble() to check for rounding errors (would also apply for KML output, or ogrinfo output)


def gml_out_precision():

    geom = ogr.CreateGeometryFromWkt('POINT(93538.15 1.23456789)')
    expected_gml = '<gml:Point><gml:coordinates>93538.15,1.23456789</gml:coordinates></gml:Point>'
    got_gml = geom.ExportToGML()
    assert got_gml == expected_gml, 'did not get expected gml'

    geom = ogr.CreateGeometryFromWkt('POINT(93538.55 1234567.89)')
    expected_gml = '<gml:Point><gml:coordinates>93538.55,1234567.89</gml:coordinates></gml:Point>'
    got_gml = geom.ExportToGML()
    assert got_gml == expected_gml, 'did not get expected gml'

###############################################################################
# Test various error cases of gml2ogrgeometry.cpp


def test_gml_invalid_geoms():

    gml_expected_wkt_list = [
        ('<?xml version="1.0" encoding="UTF-8"?>', None),
        ('<!-- bla -->', None),
        ('<foo/>', None),
        ('<gml:Point><gml:pos>31 29 16</gml:pos><gml:pos>31 29 16</gml:pos></gml:Point>', None),
        ('<gml:Point><gml:coordinates/></gml:Point>', 'POINT EMPTY'),  # This is valid GML actually
        ('<gml:Point><gml:coordinates>0</gml:coordinates></gml:Point>', None),
        ('<gml:Point><gml:coordinates>0 1</gml:coordinates></gml:Point>', 'POINT (0 1)'),  # Support for uncommon formatting of coordinates
        ('<gml:Point><gml:coordinates>0 1 2</gml:coordinates></gml:Point>', 'POINT (0 1 2)'),  # Support for uncommon formatting of coordinates
        ('<gml:Point><gml:coordinates>0,1 2,3</gml:coordinates></gml:Point>', None),
        ('<gml:Point><gml:pos>0</gml:pos></gml:Point>', None),
        ('<gml:Point><gml:pos/></gml:Point>', 'POINT EMPTY'),  # This is valid GML actually
        ('<gml:Point/>', None),
        ('<gml:Point><foo/></gml:Point>', None),
        ('<gml:LineString/>', None),
        ('<gml:LineString><foo/></gml:LineString>', None),
        ('<gml:LineString><gml:posList></gml:posList></gml:LineString>', 'LINESTRING EMPTY'),  # This is valid GML actually
        ('<gml:LineString><gml:posList>0</gml:posList></gml:LineString>', None),
        ('<gml:LineString><gml:posList srsDimension="4">0 1 2 3</gml:posList></gml:LineString>', None),
        ('<gml:LineString><gml:posList srsDimension="3">0 1 2 3</gml:posList></gml:LineString>', None),
        ('<gml:Point><gml:coord></gml:coord></gml:Point>', None),
        ('<gml:Point><gml:coord><gml:X/><gml:Y/></gml:coord></gml:Point>', None),
        ('<gml:Point><gml:coord><gml:X>0</gml:X></gml:coord></gml:Point>', None),
        ('<gml:Polygon/>', 'POLYGON EMPTY'),  # valid GML3, but invalid GML2. Be tolerant
        ('<gml:Polygon><gml:outerBoundaryIs/></gml:Polygon>', 'POLYGON EMPTY'),  # valid GML2
        ('<gml:Polygon><gml:outerBoundaryIs><foo/></gml:outerBoundaryIs></gml:Polygon>', None),
        ('<gml:Polygon><gml:outerBoundaryIs><gml:Point><gml:pos>31 29 16</gml:pos></gml:Point></gml:outerBoundaryIs></gml:Polygon>', None),
        ('<gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:posList>0 1 2 3 4 5 0 1</gml:posList></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs/></gml:Polygon>', None),
        ('<gml:Polygon><gml:outerBoundaryIs><gml:LinearRing/></gml:outerBoundaryIs><gml:innerBoundaryIs/></gml:Polygon>', None),
        ('<gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:posList>0 1 2 3 4 5 0 1</gml:posList></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs><gml:Point><gml:pos>31 29 16</gml:pos></gml:Point></gml:innerBoundaryIs></gml:Polygon>', None),
        ('<gml:Ring/>', None),
        ('<gml:Ring><foo/></gml:Ring>', None),
        ('<gml:Ring><gml:curveMember/></gml:Ring>', None),
        ('<gml:Ring><gml:curveMember><foo/></gml:curveMember></gml:Ring>', None),
        ('<gml:Ring><gml:curveMember><gml:Point><gml:pos>31 29 16</gml:pos></gml:Point></gml:curveMember></gml:Ring>', None),
        ('<gml:Box/>', None),
        ('<gml:Box><gml:pos>31 29 16</gml:pos></gml:Box>', None),
        ('<gml:MultiPolygon/>', 'MULTIPOLYGON EMPTY'),  # valid GML3, but invalid GML2. Be tolerant
        ('<gml:MultiPolygon><foo/></gml:MultiPolygon>', 'MULTIPOLYGON EMPTY'),  # illegal GML, but we are tolerant
        ('<gml:MultiPolygon><gml:polygonMember/></gml:MultiPolygon>', 'MULTIPOLYGON EMPTY'),  # valid in GML3 (accepted by PostGIS too)
        ('<gml:MultiPolygon><gml:polygonMember><foo/></gml:polygonMember></gml:MultiPolygon>', None),
        ('<gml:MultiPolygon><gml:polygonMember><gml:Point><gml:pos>31 29 16</gml:pos></gml:Point></gml:polygonMember></gml:MultiPolygon>', None),
        ('<gml:MultiSurface><gml:surfaceMembers/></gml:MultiSurface>', 'MULTIPOLYGON EMPTY'),  # valid GML
        ('<gml:MultiSurface><gml:surfaceMembers><foo/></gml:surfaceMembers></gml:MultiSurface>', 'MULTIPOLYGON EMPTY'),  # illegal GML, but we are tolerant
        ('<gml:MultiSurface><gml:surfaceMembers><gml:Polygon/></gml:surfaceMembers></gml:MultiSurface>', 'MULTIPOLYGON EMPTY'),  # valid GML3
        ('<gml:MultiPoint/>', 'MULTIPOINT EMPTY'),
        ('<gml:MultiPoint><foo/></gml:MultiPoint>', 'MULTIPOINT EMPTY'),
        ('<gml:MultiPoint><gml:pointMember/></gml:MultiPoint>', 'MULTIPOINT EMPTY'),  # valid in GML3 (accepted by PostGIS too)
        ('<gml:MultiPoint><gml:pointMember><gml:LineString><gml:posList>0 1 2 3</gml:posList></gml:LineString></gml:pointMember></gml:MultiPoint>', None),
        ('<gml:MultiPoint><gml:pointMembers></gml:pointMembers></gml:MultiPoint>', 'MULTIPOINT EMPTY'),
        ('<gml:MultiPoint><gml:pointMembers><foo/></gml:pointMembers></gml:MultiPoint>', 'MULTIPOINT EMPTY'),
        ('<gml:MultiPoint><gml:pointMembers><gml:Point/></gml:pointMembers></gml:MultiPoint>', None),
        ('<gml:MultiLineString/>', 'MULTILINESTRING EMPTY'),
        ('<gml:MultiLineString><foo/></gml:MultiLineString>', 'MULTILINESTRING EMPTY'),
        ('<gml:MultiLineString><gml:lineStringMember/></gml:MultiLineString>', None),
        ('<gml:MultiLineString><gml:lineStringMember><gml:Point><gml:pos>31 29 16</gml:pos></gml:Point></gml:lineStringMember></gml:MultiLineString>', None),
        ('<gml:MultiCurve/>', 'MULTILINESTRING EMPTY'),
        ('<gml:MultiCurve><foo/></gml:MultiCurve>', 'MULTILINESTRING EMPTY'),
        ('<gml:MultiCurve><gml:curveMember/></gml:MultiCurve>', 'MULTILINESTRING EMPTY'),  # valid in GML3 (accepted by PostGIS too)
        ('<gml:MultiCurve><gml:curveMember><foo/></gml:curveMember></gml:MultiCurve>', None),
        ('<gml:MultiCurve><gml:curveMember><gml:Curve/></gml:curveMember></gml:MultiCurve>', None),
        ('<gml:MultiCurve><gml:curveMember><gml:Curve><foo/></gml:Curve></gml:curveMember></gml:MultiCurve>', None),
        ('<gml:MultiCurve><gml:curveMember><gml:Curve><gml:Point><gml:pos>31 29 16</gml:pos></gml:Point></gml:Curve></gml:curveMember></gml:MultiCurve>', None),
        ('<gml:MultiCurve><gml:curveMembers></gml:curveMembers></gml:MultiCurve>', 'MULTILINESTRING EMPTY'),
        ('<gml:MultiCurve><gml:curveMembers><foo/></gml:curveMembers></gml:MultiCurve>', None),
        ('<gml:MultiCurve><gml:curveMembers><gml:LineString/></gml:curveMembers></gml:MultiCurve>', None),
        ('<gml:Curve/>', None),
        ('<gml:Curve><foo/></gml:Curve>', None),
        ('<gml:Curve><gml:segments/></gml:Curve>', None),
        ('<gml:Curve><gml:segments><foo/></gml:segments></gml:Curve>', None),
        ('<gml:Curve><gml:segments><gml:Point><gml:pos>31 29 16</gml:pos></gml:Point></gml:segments></gml:Curve>', None),
        ('<gml:Arc/>', None),
        ('<gml:Arc><gml:posList>0 0 0 1</gml:posList></gml:Arc>', None),
        ('<gml:Arc><gml:posList>0 0 0 1 1 0 2 0</gml:posList></gml:Arc>', None),
        ('<gml:ArcString/>', None),
        ('<gml:ArcString><gml:posList>0 0 0 1</gml:posList></gml:ArcString>', None),
        ('<gml:ArcString><gml:posList>0 0 0 1 1 0 2 0</gml:posList></gml:ArcString>', None),
        ('<gml:Circle/>', None),
        ('<gml:Circle><gml:posList>0 0 0 1</gml:posList></gml:Circle>', None),
        ('<gml:segments/>', None),
        ('<gml:segments><foo/></gml:segments>', None),
        ('<gml:segments><gml:LineStringSegment/></gml:segments>', None),
        ('<gml:segments><gml:LineStringSegment><foo/></gml:LineStringSegment></gml:segments>', None),
        ('<gml:segments><gml:LineStringSegment><gml:Point><gml:pos>31 29 16</gml:pos></gml:Point></gml:LineStringSegment></gml:segments>', None),
        ('<gml:MultiGeometry/>', 'GEOMETRYCOLLECTION EMPTY'),
        ('<gml:MultiGeometry><foo/></gml:MultiGeometry>', 'GEOMETRYCOLLECTION EMPTY'),
        ('<gml:MultiGeometry><gml:geometryMember/></gml:MultiGeometry>', 'GEOMETRYCOLLECTION EMPTY'),  # valid in GML3 (accepted by PostGIS too)
        ('<gml:MultiGeometry><gml:geometryMember><foo/></gml:geometryMember></gml:MultiGeometry>', None),
        ('<gml:MultiGeometry><gml:geometryMembers><foo/></gml:geometryMembers></gml:MultiGeometry>', None),
        ('<gml:Surface/>', 'POLYGON EMPTY'),  # valid GML3
        ('<gml:Surface><foo/></gml:Surface>', 'POLYGON EMPTY'),  # invalid GML3, but we are tolerant
        ('<gml:Surface><gml:patches/></gml:Surface>', 'POLYGON EMPTY'),  # valid GML3
        ('<gml:Surface><gml:patches><foo/></gml:patches></gml:Surface>', None),
        ('<gml:Surface><gml:patches><gml:PolygonPatch/></gml:patches></gml:Surface>', 'POLYGON EMPTY'),  # valid GML3
        ('<gml:Solid/>', 'POLYHEDRALSURFACE EMPTY'),  # valid GML3
        ('<gml:Solid><foo/></gml:Solid>', 'POLYHEDRALSURFACE EMPTY'),  # invalid GML3, but we are tolerant
        ('<gml:Solid><gml:exterior/></gml:Solid>', 'POLYHEDRALSURFACE EMPTY'),  # valid GML3
        ('<gml:Solid><gml:exterior><foo/></gml:exterior></gml:Solid>', None),
        ('<gml:Solid><gml:exterior><Polygon><exterior><LinearRing><posList srsDimension="2">0 0 4 0 4 4 0 4 0 0</posList></LinearRing></exterior></Polygon></gml:exterior><gml:interior/></gml:Solid>', 'POLYGON ((0 0,4 0,4 4,0 4,0 0))'),
        ('<gml:OrientableSurface/>', None),
        ('<gml:OrientableSurface><foo/></gml:OrientableSurface>', None),
        ('<gml:OrientableSurface><gml:baseSurface/></gml:OrientableSurface>', None),
        ('<gml:OrientableSurface><gml:baseSurface><foo/></gml:baseSurface></gml:OrientableSurface>', None),
        ('<gmlce:SimplePolygon/>', None),  # invalid
        ('<gmlce:SimplePolygon><foo/></gmlce:SimplePolygon>', None),  # invalid GML3, but we are tolerant
        ('<gmlce:SimplePolygon><gml:posList/></gmlce:SimplePolygon>', 'POLYGON EMPTY'),  # validates the schema
        ('<gmlce:SimpleMultiPoint/>', None),  # invalid
        ('<gmlce:SimpleMultiPoint><foo/></gmlce:SimpleMultiPoint>', None),  # invalid GML3, but we are tolerant
        ('<gmlce:SimpleMultiPoint><gml:posList/></gmlce:SimpleMultiPoint>', 'MULTIPOINT EMPTY'),  # validates the schema
        ('<gml:Envelope/>', None),
        ('<gml:Envelope><gml:lowerCorner/><gml:upperCorner/></gml:Envelope>', None),
        ('<gml:Envelope><gml:lowerCorner>1</gml:lowerCorner><gml:upperCorner>3 4</gml:upperCorner/></gml:Envelope>', None),
        ('<gml:Point><gml:coordinates cs="bla">1bla2</gml:coordinates></gml:Point>', None),
        ('<gml:Point><gml:coordinates cs="">1bla2</gml:coordinates></gml:Point>', None),
        ('<gml:Point><gml:coordinates cs="0">1bla2</gml:coordinates></gml:Point>', None),
        ('<gml:Point><gml:coordinates ts="bla">1,2</gml:coordinates></gml:Point>', None),
        ('<gml:Point><gml:coordinates ts="">1,2</gml:coordinates></gml:Point>', None),
        ('<gml:Point><gml:coordinates ts="0">1,2</gml:coordinates></gml:Point>', None),
        ('<gml:Point><gml:coordinates decimal="bla">1,2</gml:coordinates></gml:Point>', None),
        ('<gml:Point><gml:coordinates decimal="">1,2</gml:coordinates></gml:Point>', None),
        ('<gml:Point><gml:coordinates decimal="0">1,2</gml:coordinates></gml:Point>', None),
        ("""<gml:Curve><gml:segments>
            <gml:Arc><gml:posList>0 0 1 0 0 0</gml:posList></gml:Arc>
            <gml:LineStringSegment><gml:posList>-10 0 -1 0 0 0</gml:posList></gml:LineStringSegment>
            </gml:segments></gml:Curve>""", "COMPOUNDCURVE (CIRCULARSTRING (0 0,1 0,0 0),(0 0,-1 0,-10 0))"),  # non contiguous segments
        ("""<gml:CompositeCurve>
            <gml:curveMember><gml:Curve><gml:segments><gml:LineString><gml:posList>0 0 1 0 0 0</gml:posList></gml:LineString></gml:segments></gml:Curve></gml:curveMember>
            <gml:curveMember>
                    <gml:Curve><gml:segments>
                        <gml:Arc><gml:posList>-10 0 1 0 0 0</gml:posList></gml:Arc>
                        <gml:LineStringSegment><gml:posList>0 0 -1 0 0 0</gml:posList></gml:LineStringSegment>
                    </gml:segments></gml:Curve>
            </gml:curveMember>
            </gml:CompositeCurve>""", None),  # non contiguous segments
        ("<gml:ArcByBulge><gml:bulge>2</gml:bulge><gml:normal>-1</gml:normal></gml:ArcByBulge>", None),
        ("<gml:ArcByBulge><gml:posList>2 0</gml:posList><gml:bulge>2</gml:bulge><gml:normal>-1</gml:normal></gml:ArcByBulge>", None),
        ("<gml:ArcByBulge><gml:posList>2 0 -2 0</gml:posList><gml:normal>-1</gml:normal></gml:ArcByBulge>", None),
        ("<gml:ArcByBulge><gml:posList>2 0 -2 0</gml:posList><gml:normal>-1</gml:normal></gml:ArcByBulge>", None),
        ("<ArcByBulge><bulge/></ArcByBulge>", None),
        ("<gml:ArcByCenterPoint><gml:radius>2</gml:radius><gml:startAngle>90</gml:startAngle><gml:endAngle>270</gml:endAngle></gml:ArcByCenterPoint>", None),
        ("<gml:ArcByCenterPoint><gml:pos>1 2</gml:pos><gml:startAngle>90</gml:startAngle><gml:endAngle>270</gml:endAngle></gml:ArcByCenterPoint>", None),
        ("<gml:ArcByCenterPoint><gml:pos>1 2</gml:pos><gml:radius>2</gml:radius<gml:endAngle>270</gml:endAngle></gml:ArcByCenterPoint>", None),
        ("<gml:ArcByCenterPoint><gml:pos>1 2</gml:pos><gml:radius>2</gml:radius><gml:startAngle>90</gml:startAngle></gml:ArcByCenterPoint>", None),
        ("<gml:CircleByCenterPoint><gml:radius>2</gml:radius></gml:CircleByCenterPoint>", None),
        ("<gml:CircleByCenterPoint><gml:pos>1 2</gml:pos></gml:CircleByCenterPoint>", None),
        ('<gml:PolyhedralSurface><foo/></gml:PolyhedralSurface>', None),
        ('<gml:PolyhedralSurface><gml:polygonPatches><foo/></gml:polygonPatches></gml:PolyhedralSurface>', None),
        ('<gml:PolyhedralSurface><gml:polygonPatches><gml:PolygonPatch><gml:exterior><foo/></gml:exterior></gml:PolygonPatch></gml:polygonPatches></gml:PolyhedralSurface>', None),
    ]

    for (gml, expected_wkt) in gml_expected_wkt_list:
        gdal.PushErrorHandler('CPLQuietErrorHandler')
        # print gml
        geom = ogr.CreateGeometryFromGML(gml)
        gdal.PopErrorHandler()
        if geom is None:
            assert expected_wkt is None, \
                ('did not get expected result for %s. Got None instead of %s' % (gml, expected_wkt))
        else:
            wkt = geom.ExportToWkt()
            if expected_wkt is None:
                pytest.fail('did not get expected result for %s. Got %s instead of None' % (gml, wkt))
            else:
                assert wkt == expected_wkt, \
                    ('did not get expected result for %s. Got %s instead of %s' % (gml, wkt, expected_wkt))

    
###############################################################################
# Test write support for GML3


def test_gml_write_gml3_geometries():

    gml_list = ['<gml:Point><gml:pos>2 3</gml:pos></gml:Point>',
                '<gml:Point><gml:pos>2 3 4</gml:pos></gml:Point>',
                '<gml:LineString><gml:posList>2 3 4 5</gml:posList></gml:LineString>',
                '<gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>2 3 4 5</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>',
                '<gml:LineString><gml:posList srsDimension="3">2 3 10 4 5 20</gml:posList></gml:LineString>',
                '<gml:Curve><gml:segments><gml:LineStringSegment><gml:posList srsDimension="3">2 3 10 4 5 20</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>',
                '<gml:Polygon><gml:exterior><gml:LinearRing><gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon>',
                '<gml:Polygon><gml:exterior><gml:LinearRing><gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList></gml:LinearRing></gml:exterior><gml:interior><gml:LinearRing><gml:posList>10 10 10 11 11 11 10 10</gml:posList></gml:LinearRing></gml:interior></gml:Polygon>',
                '<gml:MultiPoint><gml:pointMember><gml:Point><gml:pos>2 3</gml:pos></gml:Point></gml:pointMember><gml:pointMember><gml:Point><gml:pos>4 5</gml:pos></gml:Point></gml:pointMember></gml:MultiPoint>',
                '<gml:MultiCurve><gml:curveMember><gml:LineString><gml:posList>0 1 2 3 4 5</gml:posList></gml:LineString></gml:curveMember><gml:curveMember><gml:LineString><gml:posList>6 7 8 9 10 11</gml:posList></gml:LineString></gml:curveMember></gml:MultiCurve>',
                '<gml:MultiCurve><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>0 1 2 3 4 5</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>6 7 8 9 10 11</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember></gml:MultiCurve>',
                '<gml:MultiSurface><gml:surfaceMember><gml:Polygon><gml:exterior><gml:LinearRing><gml:posList>0 1 2 3 4 5 0 1</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember><gml:surfaceMember><gml:Polygon><gml:exterior><gml:LinearRing><gml:posList>6 7 8 9 10 11 6 7</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember></gml:MultiSurface>',
                '<gml:MultiGeometry><gml:geometryMember><gml:Point><gml:pos>0 1</gml:pos></gml:Point></gml:geometryMember><gml:geometryMember><gml:LineString><gml:posList>2 3 4 5</gml:posList></gml:LineString></gml:geometryMember></gml:MultiGeometry>']

    for gml_in in gml_list:
        geom = ogr.CreateGeometryFromGML(gml_in)
        if gml_in.find('<gml:Curve') != -1:
            gml_out = geom.ExportToGML(['FORMAT=GML3', 'GML3_LINESTRING_ELEMENT=curve'])
        else:
            gml_out = geom.ExportToGML(['FORMAT=GML3'])
        assert gml_out == gml_in, ('got %s, instead of %s' % (gml_out, gml_in))

    
###############################################################################
# Test write support for GML3 SRS


def test_gml_write_gml3_srs():

    sr32631 = osr.SpatialReference()
    sr32631.SetFromUserInput("EPSG:32631")

    srlonglat = osr.SpatialReference()
    srlonglat.SetFromUserInput("EPSG:4326")

    srlatlong = osr.SpatialReference()
    srlatlong.SetFromUserInput("EPSGA:4326")

    geom = ogr.CreateGeometryFromWkt('POINT(500000 4500000)')
    geom.AssignSpatialReference(sr32631)
    gml3 = geom.ExportToGML(options=['FORMAT=GML3'])
    expected_gml = '<gml:Point srsName="urn:ogc:def:crs:EPSG::32631"><gml:pos>500000 4500000</gml:pos></gml:Point>'
    assert gml3 == expected_gml, ('got %s, instead of %s' % (gml3, expected_gml))

    # Should perform the needed coordinate order swapping
    geom = ogr.CreateGeometryFromWkt('POINT(2 49)')
    geom.AssignSpatialReference(srlonglat)
    gml3 = geom.ExportToGML(options=['FORMAT=GML3'])
    expected_gml = '<gml:Point srsName="urn:ogc:def:crs:EPSG::4326"><gml:pos>49 2</gml:pos></gml:Point>'
    assert gml3 == expected_gml, ('got %s, instead of %s' % (gml3, expected_gml))

    # Should not change the coordinate order.
    geom = ogr.CreateGeometryFromWkt('POINT(49 2)')
    geom.AssignSpatialReference(srlatlong)
    gml3 = geom.ExportToGML(options=['FORMAT=GML3'])
    expected_gml = '<gml:Point srsName="urn:ogc:def:crs:EPSG::4326"><gml:pos>49 2</gml:pos></gml:Point>'
    assert gml3 == expected_gml, ('got %s, instead of %s' % (gml3, expected_gml))

    # Legacy SRS format
    geom = ogr.CreateGeometryFromWkt('POINT(2 49)')
    geom.AssignSpatialReference(srlonglat)
    gml3 = geom.ExportToGML(options=['FORMAT=GML3', 'GML3_LONGSRS=NO'])
    expected_gml = '<gml:Point srsName="EPSG:4326"><gml:pos>2 49</gml:pos></gml:Point>'
    assert gml3 == expected_gml, ('got %s, instead of %s' % (gml3, expected_gml))

    # Test SRSNAME_FORMAT=SHORT
    geom = ogr.CreateGeometryFromWkt('POINT(2 49)')
    geom.AssignSpatialReference(srlonglat)
    gml3 = geom.ExportToGML(options=['FORMAT=GML3', 'SRSNAME_FORMAT=SHORT'])
    expected_gml = '<gml:Point srsName="EPSG:4326"><gml:pos>2 49</gml:pos></gml:Point>'
    assert gml3 == expected_gml, ('got %s, instead of %s' % (gml3, expected_gml))

    # Test SRSNAME_FORMAT=SRSNAME_FORMAT
    geom = ogr.CreateGeometryFromWkt('POINT(2 49)')
    geom.AssignSpatialReference(srlonglat)
    gml3 = geom.ExportToGML(options=['FORMAT=GML3', 'SRSNAME_FORMAT=OGC_URN'])
    expected_gml = '<gml:Point srsName="urn:ogc:def:crs:EPSG::4326"><gml:pos>49 2</gml:pos></gml:Point>'
    assert gml3 == expected_gml, ('got %s, instead of %s' % (gml3, expected_gml))

    # Test SRSNAME_FORMAT=OGC_URL
    geom = ogr.CreateGeometryFromWkt('POINT(2 49)')
    geom.AssignSpatialReference(srlonglat)
    gml3 = geom.ExportToGML(options=['FORMAT=GML3', 'SRSNAME_FORMAT=OGC_URL'])
    expected_gml = '<gml:Point srsName="http://www.opengis.net/def/crs/EPSG/0/4326"><gml:pos>49 2</gml:pos></gml:Point>'
    assert gml3 == expected_gml, ('got %s, instead of %s' % (gml3, expected_gml))

###############################################################################
# Test that importing too nested GML doesn't cause stack overflows


def test_gml_nested():

    gml = '<gml:MultiGeometry><gml:geometryMember>' * 31
    gml += '<gml:MultiPolygon></gml:MultiPolygon>'
    gml += '</gml:geometryMember></gml:MultiGeometry>' * 31

    geom = ogr.CreateGeometryFromGML(gml)
    assert geom is not None, 'expected a geometry'

    gml = '<gml:MultiGeometry><gml:geometryMember>' * 32
    gml += '<gml:MultiPolygon></gml:MultiPolygon>'
    gml += '</gml:geometryMember></gml:MultiGeometry>' * 32

    gdal.PushErrorHandler('CPLQuietErrorHandler')
    geom = ogr.CreateGeometryFromGML(gml)
    gdal.PopErrorHandler()
    assert geom is None, 'expected None'

###############################################################################
# Test GML 3.3 SimplePolygon


def test_gml_SimplePolygon():

    gml = """<gmlce:SimplePolygon><gml:posList>0 0 1 0 1 1 0 1</gml:posList></gmlce:SimplePolygon>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'POLYGON ((0 0,1 0,1 1,0 1,0 0))', \
        '<gmlce:SimplePolygon> not correctly parsed'

###############################################################################
# Test GML 3.3 SimpleRectangle


def test_gml_SimpleRectangle():

    gml = """<gmlce:SimpleRectangle><gml:posList>0 0 1 0 1 1 0 1</gml:posList></gmlce:SimpleRectangle>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'POLYGON ((0 0,1 0,1 1,0 1,0 0))', \
        '<gmlce:SimpleRectangle> not correctly parsed'

###############################################################################
# Test GML 3.3 SimpleTriangle


def test_gml_SimpleTriangle():

    gml = """<gmlce:SimpleTriangle><gml:posList>0 0 1 0 1 1</gml:posList></gmlce:SimpleTriangle>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'TRIANGLE ((0 0,1 0,1 1,0 0))', \
        '<gmlce:SimpleTriangle> not correctly parsed'

###############################################################################
# Test GML 3.3 SimpleMultiPoint


def test_gml_SimpleMultiPoint():

    gml = """<gmlce:SimpleMultiPoint><gml:posList>0 1 2 3</gml:posList></gmlce:SimpleMultiPoint>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'MULTIPOINT (0 1,2 3)', \
        '<gmlce:SimpleMultiPoint> not correctly parsed'

###############################################################################
# Test  gml:CompositeCurve> in <gml:Ring>


def test_gml_CompositeCurveInRing():

    gml = """<gml:Surface>
    <gml:patches>
        <gml:PolygonPatch interpolation="planar">
            <gml:exterior>
                <gml:Ring>
                    <gml:curveMember>
                        <gml:CompositeCurve>
                            <gml:curveMember>
                                <gml:Curve>
                                    <gml:segments>
                                        <gml:LineStringSegment>
                                            <gml:pos>0 0</gml:pos>
                                            <gml:pos>0 1</gml:pos>
                                        </gml:LineStringSegment>
                                    </gml:segments>
                                </gml:Curve>
                            </gml:curveMember>
                            <gml:curveMember>
                                <gml:Curve>
                                    <gml:segments>
                                        <gml:LineStringSegment>
                                            <gml:pos>0 1</gml:pos>
                                            <gml:pos>1 1</gml:pos>
                                        </gml:LineStringSegment>
                                    </gml:segments>
                                </gml:Curve>
                            </gml:curveMember>
                            <gml:curveMember>
                                <gml:Curve>
                                    <gml:segments>
                                        <gml:LineStringSegment>
                                            <gml:pos>1 1</gml:pos>
                                            <gml:pos>0 0</gml:pos>
                                        </gml:LineStringSegment>
                                    </gml:segments>
                                </gml:Curve>
                            </gml:curveMember>
                        </gml:CompositeCurve>
                    </gml:curveMember>
                </gml:Ring>
            </gml:exterior>
        </gml:PolygonPatch>
    </gml:patches>
</gml:Surface>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'POLYGON ((0 0,0 1,1 1,0 0))'

###############################################################################
# Test <gml:CompositeSurface> in <gml:surfaceMembers> (#5369)


def test_gml_CompositeSurface_in_surfaceMembers():

    gml = """<gml:MultiSurface>
          <gml:surfaceMembers>
            <gml:CompositeSurface>
              <gml:surfaceMember>
                <gml:Polygon>
                  <gml:exterior>
                    <gml:LinearRing>
                      <gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
                    </gml:LinearRing>
                  </gml:exterior>
                </gml:Polygon>
              </gml:surfaceMember>
              <gml:surfaceMember>
                <gml:Polygon>
                  <gml:exterior>
                    <gml:LinearRing>
                      <gml:posList>2 0 2 1 3 1 3 0 2 0</gml:posList>
                    </gml:LinearRing>
                  </gml:exterior>
                </gml:Polygon>
              </gml:surfaceMember>
            </gml:CompositeSurface>
          </gml:surfaceMembers>
        </gml:MultiSurface>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'MULTIPOLYGON (((0 0,0 1,1 1,1 0,0 0)),((2 0,2 1,3 1,3 0,2 0)))'

###############################################################################
# Test <gml:PolygonPatch> with only Interior ring (#5421)


def test_gml_MultiSurfaceOfSurfaceOfPolygonPatchWithInteriorRing():

    gml = """<gml:MultiSurface>
               <gml:surfaceMember>
                 <gml:Surface>
                    <gml:patches>
                      <gml:PolygonPatch>
                        <gml:exterior>
                          <gml:LinearRing>
                            <gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
                          </gml:LinearRing>
                        </gml:exterior>
                      </gml:PolygonPatch>
                    </gml:patches>
                  </gml:Surface>
                </gml:surfaceMember>
                <gml:surfaceMember>
                  <gml:Surface>
                    <gml:patches>
                      <gml:PolygonPatch>
                        <gml:interior>
                          <gml:LinearRing>
                            <gml:posList>0.25 0.25 0.25 0.75 0.75 0.75 0.75 0.25 0.25 0.25</gml:posList>
                          </gml:LinearRing>
                        </gml:interior>
                      </gml:PolygonPatch>
                    </gml:patches>
                  </gml:Surface>
                </gml:surfaceMember>
               <gml:surfaceMember>
                 <gml:Surface>
                    <gml:patches>
                      <gml:PolygonPatch>
                        <gml:exterior>
                          <gml:LinearRing>
                            <gml:posList>0 0 0 -1 -1 -1 -1 0 0 0</gml:posList>
                          </gml:LinearRing>
                        </gml:exterior>
                      </gml:PolygonPatch>
                    </gml:patches>
                  </gml:Surface>
                </gml:surfaceMember>
              </gml:MultiSurface>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'MULTIPOLYGON (((0 0,0 1,1 1,1 0,0 0),(0.25 0.25,0.25 0.75,0.75 0.75,0.75 0.25,0.25 0.25)),((0 0,0 -1,-1 -1,-1 0,0 0)))'

###############################################################################
# Test ts, cs and decimal attributes of gml:coordinates


def test_gml_Coordinates_ts_cs_decimal():

    gml_expected_wkt_list = [
        ('<gml:Point><gml:coordinates>1,2</gml:coordinates></gml:Point>', 'POINT (1 2)'),  # default values
        ('<gml:Point><gml:coordinates cs="," ts=" " decimal=".">1,2</gml:coordinates></gml:Point>', 'POINT (1 2)'),  # default values
        ('<gml:Point><gml:coordinates cs="," ts=" " decimal=".">1,2,3</gml:coordinates></gml:Point>', 'POINT (1 2 3)'),  # default values
        ('<gml:Point><gml:coordinates cs="," ts=" " decimal=".">  1,2  </gml:coordinates></gml:Point>', 'POINT (1 2)'),  # we accept that...
        ('<gml:Point><gml:coordinates>1 2</gml:coordinates></gml:Point>', 'POINT (1 2)'),  # this is completely out of specification ! but we accept that too !
        ('<gml:Point><gml:coordinates cs=";">1;2</gml:coordinates></gml:Point>', 'POINT (1 2)'),
        ('<gml:Point><gml:coordinates decimal="," cs=";">1,2;3,4</gml:coordinates></gml:Point>', 'POINT (1.2 3.4)'),
        ('<gml:Point><gml:coordinates decimal="," cs=";">1,2;3,4;5,6</gml:coordinates></gml:Point>', 'POINT (1.2 3.4 5.6)'),
        ('<gml:LineString><gml:coordinates>1,2 3,4</gml:coordinates></gml:LineString>', 'LINESTRING (1 2,3 4)'),  # default values
        ('<gml:LineString><gml:coordinates cs="," ts=" " decimal=".">1,2 3,4</gml:coordinates></gml:LineString>', 'LINESTRING (1 2,3 4)'),  # default values
        ('<gml:LineString><gml:coordinates cs="," ts=" " decimal=".">1,2,2.5 3,4</gml:coordinates></gml:LineString>', 'LINESTRING (1 2 2.5,3 4 0)'),  # default values
        ('<gml:LineString><gml:coordinates ts="-">1,2-3,4</gml:coordinates></gml:LineString>', 'LINESTRING (1 2,3 4)'),
        ('<gml:LineString><gml:coordinates cs=" " ts=",">1 2,3 4</gml:coordinates></gml:LineString>', 'LINESTRING (1 2,3 4)'),
        ('<gml:LineString><gml:coordinates cs=" " ts=",">1 2 2.5,3 4</gml:coordinates></gml:LineString>', 'LINESTRING (1 2 2.5,3 4 0)'),
    ]

    for (gml, expected_wkt) in gml_expected_wkt_list:
        geom = ogr.CreateGeometryFromGML(gml)
        wkt = geom.ExportToWkt()
        if expected_wkt is None:
            pytest.fail('did not get expected result for %s. Got %s instead of None' % (gml, wkt))
        else:
            assert wkt == expected_wkt, \
                ('did not get expected result for %s. Got %s instead of %s' % (gml, wkt, expected_wkt))

    
###############################################################################
# Test gml with XML header and comments


def test_gml_with_xml_header_and_comments():

    gml_expected_wkt_list = [
        ('<?xml version="1.0" encoding="UTF-8"?><!-- comment --><gml:Point> <!-- comment --> <gml:coordinates>1,2</gml:coordinates></gml:Point>', 'POINT (1 2)'),
        ("""<gml:MultiSurface><!-- comment -->
               <gml:surfaceMember><!-- comment -->
                 <gml:Surface><!-- comment -->
                    <gml:patches><!-- comment -->
                      <gml:PolygonPatch><!-- comment -->
                        <gml:exterior><!-- comment -->
                          <gml:LinearRing><!-- comment -->
                            <gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList>
                          </gml:LinearRing>
                        </gml:exterior>
                        <!-- comment -->
                        <gml:interior><!-- comment -->
                          <gml:LinearRing><!-- comment -->
                            <gml:posList>0.25 0.25 0.25 0.75 0.75 0.75 0.75 0.25 0.25 0.25</gml:posList>
                          </gml:LinearRing>
                        </gml:interior>
                      </gml:PolygonPatch>
                    </gml:patches>
                  </gml:Surface>
                </gml:surfaceMember>
              </gml:MultiSurface>""", 'MULTIPOLYGON (((0 0,0 1,1 1,1 0,0 0),(0.25 0.25,0.25 0.75,0.75 0.75,0.75 0.25,0.25 0.25)))'),
    ]

    for (gml, expected_wkt) in gml_expected_wkt_list:
        geom = ogr.CreateGeometryFromGML(gml)
        wkt = geom.ExportToWkt()
        if expected_wkt is None:
            pytest.fail('did not get expected result for %s. Got %s instead of None' % (gml, wkt))
        else:
            assert wkt == expected_wkt, \
                ('did not get expected result for %s. Got %s instead of %s' % (gml, wkt, expected_wkt))

    
###############################################################################
# Test srsDimension attribute on top-level geometry and not on posList (#5606)


def test_gml_srsDimension_topgeometry():

    gml = """<gml:Surface srsName="EPSG:25832" srsDimension="3">
    <gml:patches>
        <gml:PolygonPatch>
            <gml:exterior>
                <gml:LinearRing>
                    <gml:posList>
                        0 0 10 0 1 10 1 1 10 1 0 10 0 0 10
                    </gml:posList>
                </gml:LinearRing>
            </gml:exterior>
        </gml:PolygonPatch>
    </gml:patches>
</gml:Surface>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert geom.ExportToWkt() == 'POLYGON ((0 0 10,0 1 10,1 1 10,1 0 10,0 0 10))'

###############################################################################
# Test GML Arc


def test_gml_Arc():

    gml = "<gml:Arc><gml:posList>1 0 0 1 -1 0</gml:posList></gml:Arc>"
    geom = ogr.CreateGeometryFromGML(gml)

    assert ogrtest.check_feature_geometry(geom, ogr.CreateGeometryFromWkt('CIRCULARSTRING (1 0,0 1,-1 0)')) == 0

    gml2 = geom.ExportToGML(['FORMAT=GML3'])
    expected_gml2 = '<gml:Curve><gml:segments><gml:ArcString><gml:posList>1 0 0 1 -1 0</gml:posList></gml:ArcString></gml:segments></gml:Curve>'
    assert gml2 == expected_gml2

    geom2 = ogr.CreateGeometryFromGML(gml2)
    assert geom.Equals(geom2)

###############################################################################
# Test GML ArcByBulge


def test_gml_ArcByBulge():

    gml = "<gml:ArcByBulge><gml:posList>2 0 -2 0</gml:posList><gml:bulge>2</gml:bulge><gml:normal>-1</gml:normal></gml:ArcByBulge>"
    geom = ogr.CreateGeometryFromGML(gml)

    assert ogrtest.check_feature_geometry(geom, ogr.CreateGeometryFromWkt('CIRCULARSTRING (2 0,0 2,-2 0)')) == 0

###############################################################################
# Test GML ArcByCenterPoint


def test_gml_ArcByCenterPoint():

    gml = "<gml:ArcByCenterPoint><gml:pos>1 2</gml:pos><gml:radius>2</gml:radius><gml:startAngle>90</gml:startAngle><gml:endAngle>270</gml:endAngle></gml:ArcByCenterPoint>"
    geom = ogr.CreateGeometryFromGML(gml)

    assert ogrtest.check_feature_geometry(geom, ogr.CreateGeometryFromWkt('CIRCULARSTRING (1 4,-1 2,1 0)')) == 0


###############################################################################
# Test compound curve of ArcByCenterPoint whose ends don't exactly match
# with ends of neighbouring curves, as found in some AIXM files

def test_gml_CompoundCurve_of_ArcByCenterPoint():

    gml = """
<Surface gml:id="Surface1" srsDimension="2" srsName="URN:OGC:DEF:CRS:OGC:1.3:CRS84">
  <patches>
    <PolygonPatch>
      <exterior>
        <Ring>
          <curveMember>
            <Curve ns:id="Curve1">
              <segments>
                <LineStringSegment>
                  <pos>-80.40 33.86</pos>
                  <pos>-80.27 33.63</pos>
                </LineStringSegment>
              </segments>
            </Curve>
          </curveMember>
          <curveMember>
            <Curve ns:id="Curve2">
              <segments>
                <ArcByCenterPoint numArc="1">
                  <pointProperty>
                    <Point ns:id="Point1">
                      <pos>-80.47 33.98</pos>
                    </Point>
                  </pointProperty>
                  <radius uom="NM">23</radius>
                  <startAngle uom="deg">295</startAngle>
                  <endAngle uom="deg">249</endAngle>
                </ArcByCenterPoint>
              </segments>
            </Curve>
          </curveMember>
          <curveMember>
            <Curve ns:id="Curve3">
              <segments>
                <LineStringSegment>
                  <pos>-80.63 33.62</pos>
                  <pos>-80.39 33.85</pos>
                </LineStringSegment>
              </segments>
            </Curve>
          </curveMember>
        </Ring>
      </exterior>
    </PolygonPatch>
  </patches>
</Surface>"""
    geom = ogr.CreateGeometryFromGML(gml)

    assert ogrtest.check_feature_geometry(geom, ogr.CreateGeometryFromWkt('POLYGON ((-80.4 33.86,-80.27 33.63,-80.305028054229538 33.622017309598967,-80.335422529369936 33.613343178471617,-80.366464292754429 33.606448070493634,-80.398003921948742 33.601365147653873,-80.429889693662162 33.598118851265042,-80.461968286017793 33.596724788982847,-80.494085487001527 33.597189662699385,-80.52608690656875 33.599511237590342,-80.557818688893789 33.603678352435914,-80.589128223167393 33.609670971175497,-80.619864849221443 33.617460275496377,-80.63 33.62,-80.39 33.85))')) == 0

###############################################################################
# Test GML CircleByCenterPoint


def test_gml_CircleByCenterPoint():

    gml = "<gml:CircleByCenterPoint><gml:pos>1 2</gml:pos><gml:radius>2</gml:radius></gml:CircleByCenterPoint>"
    geom = ogr.CreateGeometryFromGML(gml)

    assert ogrtest.check_feature_geometry(geom, ogr.CreateGeometryFromWkt('CIRCULARSTRING (-1 2,3 2,-1 2)')) == 0

###############################################################################
# Test GML Circle


def test_gml_Circle():

    gml = """<gml:Curve><gml:segments><gml:Circle>
             <gml:posList>-1 0 0 1 -0.707106781186547 -0.707106781186548</gml:posList>
             </gml:Circle></gml:segments></gml:Curve>"""

    geom = ogr.CreateGeometryFromGML(gml)

    expected_wkt = 'CIRCULARSTRING (-1 0,0 1,-0.707106781186547 -0.707106781186548,-0.923879532511287 -0.38268343236509,-1 0)'
    assert ogrtest.check_feature_geometry(geom, ogr.CreateGeometryFromWkt(expected_wkt)) == 0

    geom = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,2 0,0 0)')
    gml2 = geom.ExportToGML(['FORMAT=GML3'])
    expected_gml2 = '<gml:Curve><gml:segments><gml:Circle><gml:posList>0 0 1 1 2 0</gml:posList></gml:Circle></gml:segments></gml:Curve>'
    assert gml2 == expected_gml2

    geom2 = ogr.CreateGeometryFromGML(gml2)
    assert geom2.ExportToWkt() == 'CIRCULARSTRING (0 0,1 1,2 0,1 -1,0 0)'

    geom = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0 10,2 0 10,0 0 10)')
    gml2 = geom.ExportToGML(['FORMAT=GML3'])
    expected_gml2 = '<gml:Curve><gml:segments><gml:Circle><gml:posList srsDimension="3">0 0 10 1 1 10 2 0 10</gml:posList></gml:Circle></gml:segments></gml:Curve>'
    assert gml2 == expected_gml2

    gml = """<gml:PolygonPatch>
                <gml:exterior>
                    <gml:Ring>
                        <gml:curveMember>
                            <gml:Curve>
                                <gml:segments>
                                    <gml:Circle>
                                        <gml:posList>-1 0 0 1 -0.707106781186547 -0.707106781186548</gml:posList>
                                    </gml:Circle>
                                </gml:segments>
                            </gml:Curve>
                        </gml:curveMember>
                    </gml:Ring>
                </gml:exterior>
            </gml:PolygonPatch>"""

    geom = ogr.CreateGeometryFromGML(gml)

    expected_wkt = 'CURVEPOLYGON ( CIRCULARSTRING (-1 0,0 1,-0.707106781186547 -0.707106781186548,-0.923879532511287 -0.38268343236509,-1 0))'
    assert ogrtest.check_feature_geometry(geom, ogr.CreateGeometryFromWkt(expected_wkt)) == 0

###############################################################################
# Test ArcString


def test_gml_ArcString():

    gml = """<gml:ArcString><gml:posList srsDimension="2">-2 0 -1 -1 0 0</gml:posList></gml:ArcString>"""
    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'CIRCULARSTRING (-2 0,-1 -1,0 0)'

    gml = """<gml:ArcString><gml:posList srsDimension="2">-2 0 -1 -1 0 0 1 -1 2 0 0 2 -2 0</gml:posList></gml:ArcString>"""
    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'CIRCULARSTRING (-2 0,-1 -1,0 0,1 -1,2 0,0 2,-2 0)'

    gml2 = geom.ExportToGML(['FORMAT=GML3'])
    expected_gml2 = '<gml:Curve><gml:segments><gml:ArcString><gml:posList>-2 0 -1 -1 0 0 1 -1 2 0 0 2 -2 0</gml:posList></gml:ArcString></gml:segments></gml:Curve>'
    assert gml2 == expected_gml2

    geom2 = ogr.CreateGeometryFromGML(gml2)
    assert geom2.ExportToWkt() == 'CIRCULARSTRING (-2 0,-1 -1,0 0,1 -1,2 0,0 2,-2 0)'

###############################################################################
# Test OGRCompoundCurve


def test_gml_OGRCompoundCurve():

    wkt = 'COMPOUNDCURVE ((0 0,1 1,2 0))'
    geom = ogr.CreateGeometryFromWkt(wkt)
    gml = geom.ExportToGML(['FORMAT=GML3'])
    expected_gml = '<gml:CompositeCurve><gml:curveMember><gml:LineString><gml:posList>0 0 1 1 2 0</gml:posList></gml:LineString></gml:curveMember></gml:CompositeCurve>'
    assert gml == expected_gml

    # CompositeCurve of LineStringSegment
    gml = expected_gml
    geom = ogr.CreateGeometryFromGML(gml)
    # We simplify it in LINESTRING
    assert geom.ExportToWkt() == 'LINESTRING (0 0,1 1,2 0)'

    # CompositeCurve of Arc
    gml = """<gml:CompositeCurve><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>0 0 1 1 2 0</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:CompositeCurve>"""
    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'COMPOUNDCURVE (CIRCULARSTRING (0 0,1 1,2 0))'

    gml2 = geom.ExportToGML(['FORMAT=GML3'])
    assert gml2 == gml

    # CompositeCurve of 3 arcs
    gml = """<gml:CompositeCurve>
    <gml:curveMember><gml:Curve><gml:segments><gml:Arc><gml:posList>0 0 1 1 2 0</gml:posList></gml:Arc></gml:segments></gml:Curve></gml:curveMember>
    <gml:curveMember><gml:Curve><gml:segments><gml:Arc><gml:posList>2 0 3 1 4 0</gml:posList></gml:Arc></gml:segments></gml:Curve></gml:curveMember>
    <gml:curveMember><gml:Curve><gml:segments><gml:Arc><gml:posList>4 0 5 1 6 0</gml:posList></gml:Arc></gml:segments></gml:Curve></gml:curveMember>
    </gml:CompositeCurve>"""
    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'COMPOUNDCURVE (CIRCULARSTRING (0 0,1 1,2 0),CIRCULARSTRING (2 0,3 1,4 0),CIRCULARSTRING (4 0,5 1,6 0))'

    # Alternative syntax : Curve with 3 Arc segments
    gml = """<gml:Curve><gml:segments>
            <gml:Arc><gml:posList>0 0 1 1 2 0</gml:posList></gml:Arc>
            <gml:Arc><gml:posList>2 0 3 1 4 0</gml:posList></gml:Arc>
            <gml:Arc><gml:posList>4 0 5 1 6 0</gml:posList></gml:Arc>
            </gml:segments></gml:Curve>"""
    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'COMPOUNDCURVE (CIRCULARSTRING (0 0,1 1,2 0),CIRCULARSTRING (2 0,3 1,4 0),CIRCULARSTRING (4 0,5 1,6 0))'

    # Curve with LineStringSegment and Arc segments
    gml = """<gml:Curve><gml:segments>
            <gml:Arc><gml:posList>0 0 1 0 0 0</gml:posList></gml:Arc>
            <gml:LineStringSegment><gml:posList>0 0 -1 0 0 0</gml:posList></gml:LineStringSegment>
            </gml:segments></gml:Curve>"""
    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'COMPOUNDCURVE (CIRCULARSTRING (0 0,1 0,0 0),(0 0,-1 0,0 0))'

    # Composite curve of a LineString and a (Composite) Curve with an Arc and a LineString
    gml = """<gml:CompositeCurve>
    <gml:curveMember><gml:Curve><gml:segments><gml:LineString><gml:posList>0 0 1 0 0 0</gml:posList></gml:LineString></gml:segments></gml:Curve></gml:curveMember>
    <gml:curveMember>
            <gml:Curve><gml:segments>
                <gml:Arc><gml:posList>0 0 1 0 0 0</gml:posList></gml:Arc>
                <gml:LineStringSegment><gml:posList>0 0 -1 0 0 0</gml:posList></gml:LineStringSegment>
            </gml:segments></gml:Curve>
    </gml:curveMember>
    </gml:CompositeCurve>"""
    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'COMPOUNDCURVE ((0 0,1 0,0 0),CIRCULARSTRING (0 0,1 0,0 0),(0 0,-1 0,0 0))'

###############################################################################
# Test OGRCurvePolygon


def test_gml_OGRCurvePolygon():

    # Test one CircularString
    gml = """<gml:Polygon><gml:exterior><gml:Ring><gml:curveMember><gml:Arc><gml:posList>0 0 1 0 0 0</gml:posList></gml:Arc></gml:curveMember></gml:Ring></gml:exterior></gml:Polygon>"""
    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'CURVEPOLYGON (CIRCULARSTRING (0 0,1 0,0 0))'

    gml2 = geom.ExportToGML(['FORMAT=GML3'])
    expected_gml2 = '<gml:Polygon><gml:exterior><gml:Curve><gml:segments><gml:Circle><gml:posList>0 0 0.5 0.5 1 0</gml:posList></gml:Circle></gml:segments></gml:Curve></gml:exterior></gml:Polygon>'
    assert gml2 == expected_gml2

    # Test two CircularString
    gml = """<gml:Polygon><gml:exterior><gml:Ring><gml:curveMember><gml:Arc><gml:posList>0 0 1 0 0 0</gml:posList></gml:Arc></gml:curveMember></gml:Ring></gml:exterior><gml:interior><gml:Ring><gml:curveMember><gml:Arc><gml:posList>0.25 0 0.75 0 0.25 0</gml:posList></gml:Arc></gml:curveMember></gml:Ring></gml:interior></gml:Polygon>"""
    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'CURVEPOLYGON (CIRCULARSTRING (0 0,1 0,0 0),CIRCULARSTRING (0.25 0.0,0.75 0.0,0.25 0.0))'

    # Test a LinearRing followed by a CircularString
    gml = """<gml:Polygon><gml:exterior><gml:LinearRing><gml:posList>-2 -2 -2 2 2 2 2 -2 -2 -2</gml:posList></gml:LinearRing></gml:exterior><gml:interior><gml:Ring><gml:curveMember><gml:Arc><gml:posList>0.25 0 0.75 0 0.25 0</gml:posList></gml:Arc></gml:curveMember></gml:Ring></gml:interior></gml:Polygon>"""
    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'CURVEPOLYGON ((-2 -2,-2 2,2 2,2 -2,-2 -2),CIRCULARSTRING (0.25 0.0,0.75 0.0,0.25 0.0))'

    # Test a CircularString followed by a LinearRing
    gml = """<gml:Polygon><gml:exterior><gml:Ring><gml:curveMember><gml:Circle><gml:posList>-1 0 1 2 3 0</gml:posList></gml:Circle></gml:curveMember></gml:Ring></gml:exterior><gml:interior><gml:LinearRing><gml:posList>-2 -2 -2 2 2 2 2 -2 -2 -2</gml:posList></gml:LinearRing></gml:interior></gml:Polygon>"""
    geom = ogr.CreateGeometryFromGML(gml)
    assert ogrtest.check_feature_geometry(geom, 'CURVEPOLYGON (CIRCULARSTRING (-1 0,1 2,3 0,1.0 -2.0,-1 0),(-2 -2,-2 2,2 2,2 -2,-2 -2))') == 0, \
        geom.ExportToWkt()

    gml2 = geom.ExportToGML(['FORMAT=GML3'])
    geom2 = ogr.CreateGeometryFromGML(gml)
    expected_gml2 = '<gml:Polygon><gml:exterior><gml:Curve><gml:segments><gml:ArcString><gml:posList>-1 0 1 2 3 0 1 -2 -1 0</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:exterior><gml:interior><gml:LineString><gml:posList>-2 -2 -2 2 2 2 2 -2 -2 -2</gml:posList></gml:LineString></gml:interior></gml:Polygon>'
    expected_geom2 = ogr.CreateGeometryFromGML(expected_gml2)
    assert ogrtest.check_feature_geometry(geom2, expected_geom2) == 0, gml2

###############################################################################
# Test OGRMultiSurface


def test_gml_OGRMultiSurface():

    # MultiSurface of CurvePolygon
    gml = """<gml:MultiSurface>
    <gml:surfaceMember>
        <gml:Surface>
            <gml:patches>
                <gml:PolygonPatch>
                    <gml:exterior>
                        <gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:Circle><gml:posList>0 0 1 1 1 -1</gml:posList></gml:Circle></gml:segments></gml:Curve></gml:curveMember></gml:Ring>
                    </gml:exterior>
                </gml:PolygonPatch>
            </gml:patches>
        </gml:Surface>
    </gml:surfaceMember>
</gml:MultiSurface>"""

    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'MULTISURFACE (CURVEPOLYGON (CIRCULARSTRING (0 0,1 1,1 -1,0.292893218813453 -0.707106781186548,0 0)))', \
        '<gml:MultiSurface> not correctly parsed'

    # MultiSurface of Polygon and CurvePolygon
    gml = """<gml:MultiSurface>
    <gml:surfaceMember>
        <gml:Polygon>
            <gml:exterior>
                <gml:LinearRing><gml:posList>0 0 0 1 1 1 0 0</gml:posList></gml:LinearRing>
            </gml:exterior>
        </gml:Polygon>
    </gml:surfaceMember>
    <gml:surfaceMember>
        <gml:Polygon>
            <gml:exterior>
                <gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:Circle><gml:posList>0 0 1 1 1 -1</gml:posList></gml:Circle></gml:segments></gml:Curve></gml:curveMember></gml:Ring>
            </gml:exterior>
        </gml:Polygon>
    </gml:surfaceMember>
</gml:MultiSurface>"""

    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'MULTISURFACE (((0 0,0 1,1 1,0 0)),CURVEPOLYGON (CIRCULARSTRING (0 0,1 1,1 -1,0.292893218813453 -0.707106781186548,0 0)))', \
        '<gml:MultiSurface> not correctly parsed'

    # MultiSurface of CurvePolygon and Polygon
    gml = """<gml:MultiSurface>
    <gml:surfaceMember>
        <gml:Polygon>
            <gml:exterior>
                <gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:Circle><gml:posList>0 0 1 1 1 -1</gml:posList></gml:Circle></gml:segments></gml:Curve></gml:curveMember></gml:Ring>
            </gml:exterior>
        </gml:Polygon>
    </gml:surfaceMember>
    <gml:surfaceMember>
        <gml:Polygon>
            <gml:exterior>
                <gml:LinearRing><gml:posList>0 0 0 1 1 1 0 0</gml:posList></gml:LinearRing>
            </gml:exterior>
        </gml:Polygon>
    </gml:surfaceMember>
</gml:MultiSurface>"""

    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'MULTISURFACE (CURVEPOLYGON (CIRCULARSTRING (0 0,1 1,1 -1,0.292893218813453 -0.707106781186548,0 0)),((0 0,0 1,1 1,0 0)))', \
        '<gml:MultiSurface> not correctly parsed'

    geom = ogr.CreateGeometryFromWkt('MULTISURFACE (CURVEPOLYGON((0 0,0 1,1 1,1 0,0 0)))')
    gml2 = geom.ExportToGML(['FORMAT=GML3'])
    expected_gml2 = '<gml:MultiSurface><gml:surfaceMember><gml:Polygon><gml:exterior><gml:LinearRing><gml:posList>0 0 0 1 1 1 1 0 0 0</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember></gml:MultiSurface>'
    assert gml2 == expected_gml2

###############################################################################
# Test OGRMultiCurve


def test_gml_OGRMultiCurve():

    # MultiCurve of Arc
    gml = """<gml:MultiCurve><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>0 0 1 1 1 -1</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:MultiCurve>"""

    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'MULTICURVE (CIRCULARSTRING (0 0,1 1,1 -1))', \
        '<gml:MultiCurve> not correctly parsed'

    gml2 = geom.ExportToGML(['FORMAT=GML3'])
    assert gml2 == gml

    # MultiCurve of LineString and Arc
    gml = """<gml:MultiCurve>
    <gml:curveMember>
        <gml:LineString><gml:posList>0 0 1 1 1 -1</gml:posList></gml:LineString>
    </gml:curveMember>
    <gml:curveMember>
        <gml:Curve>
            <gml:segments><gml:Arc><gml:posList>0 0 1 1 1 -1</gml:posList></gml:Arc></gml:segments>
        </gml:Curve>
    </gml:curveMember>
</gml:MultiCurve>"""

    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'MULTICURVE ((0 0,1 1,1 -1),CIRCULARSTRING (0 0,1 1,1 -1))', \
        '<gml:MultiCurve> not correctly parsed'

    # MultiCurve of Arc and LineString
    gml = """<gml:MultiCurve>
    <gml:curveMember>
        <gml:Curve>
            <gml:segments><gml:Arc><gml:posList>0 0 1 1 1 -1</gml:posList></gml:Arc></gml:segments>
        </gml:Curve>
    </gml:curveMember>
    <gml:curveMember>
        <gml:LineString><gml:posList>0 0 1 1 1 -1</gml:posList></gml:LineString>
    </gml:curveMember>
</gml:MultiCurve>"""

    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'MULTICURVE (CIRCULARSTRING (0 0,1 1,1 -1),(0 0,1 1,1 -1))', \
        '<gml:MultiCurve> not correctly parsed'

    # MultiCurve of CompositeCurve
    gml = """<gml:MultiCurve>
    <gml:curveMember>
        <gml:CompositeCurve>
            <gml:curveMember>
                <gml:Curve>
                    <gml:segments><gml:Arc><gml:posList>0 0 1 1 1 -1</gml:posList></gml:Arc></gml:segments>
                </gml:Curve>
            </gml:curveMember>
            <gml:curveMember>
                <gml:LineString><gml:posList>1 -1 1 1 1 -1</gml:posList></gml:LineString>
            </gml:curveMember>
        </gml:CompositeCurve>
    </gml:curveMember>
</gml:MultiCurve>"""

    geom = ogr.CreateGeometryFromGML(gml)
    assert geom.ExportToWkt() == 'MULTICURVE (COMPOUNDCURVE (CIRCULARSTRING (0 0,1 1,1 -1),(1 -1,1 1,1 -1)))', \
        '<gml:MultiCurve> not correctly parsed'

###############################################################################
# Test write support for GML namespace declaration


def test_gml_write_gml_ns():

    geom = ogr.CreateGeometryFromWkt('POINT(500000 4500000)')
    gml = geom.ExportToGML(options=['NAMESPACE_DECL=YES'])
    expected_gml = '<gml:Point xmlns:gml="http://www.opengis.net/gml"><gml:coordinates>500000,4500000</gml:coordinates></gml:Point>'
    assert gml == expected_gml, ('got %s, instead of %s' % (gml, expected_gml))

    geom = ogr.CreateGeometryFromWkt('POINT(500000 4500000)')
    gml = geom.ExportToGML(options=['FORMAT=GML3', 'NAMESPACE_DECL=YES'])
    expected_gml = '<gml:Point xmlns:gml="http://www.opengis.net/gml"><gml:pos>500000 4500000</gml:pos></gml:Point>'
    assert gml == expected_gml, ('got %s, instead of %s' % (gml, expected_gml))

    geom = ogr.CreateGeometryFromWkt('POINT(500000 4500000)')
    gml = geom.ExportToGML(options=['FORMAT=GML32', 'GMLID=foo', 'NAMESPACE_DECL=YES'])
    expected_gml = '<gml:Point xmlns:gml="http://www.opengis.net/gml/3.2" gml:id="foo"><gml:pos>500000 4500000</gml:pos></gml:Point>'
    assert gml == expected_gml, ('got %s, instead of %s' % (gml, expected_gml))

###############################################################################
# When imported build a list of units based on the files available.

# print 'hit enter'
# sys.stdin.readline()




