#!/usr/bin/env pytest
# -*- coding: utf-8 -*-
###############################################################################
# $Id$
#
# 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 spatialys.com>
#
# 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 gdaltest
import ogrtest
import pytest

from osgeo import gdal, ogr, osr

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


@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)

    ogrtest.check_feature_geometry(geom_wkt, geom_gml, 0.0000000000001)


###############################################################################
# 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):
    __tracebackhide__ = True

    geom = ogr.CreateGeometryFromWkt(wkt)

    assert geom is not None, "Import geometry from WKT failed"

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

    assert srs is not None, "SRS import from EPSG failed"

    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,3 2,3 4,1 4,1 2))"
    ), "<gml:Box> not correctly parsed"


###############################################################################
# Test gml:null


def test_gml_null():

    gml = """<gml:null>unknown</gml:null>"""

    gdal.ErrorReset()
    geom = ogr.CreateGeometryFromGML(gml)
    assert geom is None
    assert gdal.GetLastErrorMsg() == ""


###############################################################################
# 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"

    gml = """<gml:Surface>
                <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:Surface>"""

    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")


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


def test_gml_Surface_with_curve_polygon_then_curve_polygon():

    gml = """<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: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)

    assert (
        geom.ExportToIsoWkt()
        == "MULTISURFACE (((0 0,0 1,1 1,1 0,0 0)),CURVEPOLYGON (COMPOUNDCURVE ((0 -1,0 1),CIRCULARSTRING (0 1,1 0,0 -1))))"
    )


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


def test_gml_Surface_with_curve_polygon_then_polygon_then_curve_polygon():

    gml = """<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: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: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)

    assert (
        geom.ExportToIsoWkt()
        == "MULTISURFACE (((0 0,0 1,1 1,1 0,0 0)),((0 0,0 1,1 1,1 0,0 0)),CURVEPOLYGON (COMPOUNDCURVE ((0 -1,0 1),CIRCULARSTRING (0 1,1 0,0 -1))))"
    )


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


def test_gml_Surface_mix_of_triangle_and_rectangle():

    gml = """<gml:Surface>
                <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:Rectangle>
                        <gml:exterior>
                            <gml:LinearRing>
                                <gml:posList srsDimension="3">0 0 10 0 1 10 1 1 10 1 0 10 0 0 10</gml:posList>
                             </gml:LinearRing>
                        </gml:exterior>
                     </gml:Rectangle>
                </gml:patches>
            </gml:Surface>"""

    geom = ogr.CreateGeometryFromGML(gml)

    assert (
        geom.ExportToIsoWkt()
        == "GEOMETRYCOLLECTION Z (TRIANGLE Z ((0 0 0,0 0 1,0 1 0,0 0 0)),POLYGON Z ((0 0 10,0 1 10,1 1 10,1 0 10,0 0 10)))"
    )


###############################################################################
# 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)))"
    )
    ogrtest.check_feature_geometry(geom, expected_wkt)

    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


@gdaltest.disable_exceptions()
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:Polygon><gml:exterior><gml:CompositeCurve/></gml:exterior></gml:Polygon>",
            None,
        ),
        (
            "<gml:Polygon><gml:exterior><gml:LinearRing><gml:posList>0 0 4 0 4 4 0 4 0 0<gml:/posList><gml:/LinearRing><gml:/exterior><gml:interior><gml:CompositeCurve/></gml:interior></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,
        ),
        (
            "<gml:Triangle><gml:exterior><gml:CompositeCurve/></gml:exterior></gml:Triangle>",
            None,
        ),
        ("<gml:TriangulatedSurface></gml:TriangulatedSurface>", None),
        (
            "<gml:TriangulatedSurface><gml:patches><gml:Triangle/></gml:patches></gml:TriangulatedSurface>",
            None,
        ),
    ]

    for (gml, expected_wkt) in gml_expected_wkt_list:
        with gdal.quiet_errors():
            # print gml
            geom = ogr.CreateGeometryFromGML(gml)
        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")
    srlonglat.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER)

    srlatlong = osr.SpatialReference()
    srlatlong.SetFromUserInput("EPSG:4326")
    srlatlong.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)

    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

    with pytest.raises(Exception):
        ogr.CreateGeometryFromGML(gml)


###############################################################################
# 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)

    ogrtest.check_feature_geometry(
        geom, ogr.CreateGeometryFromWkt("CIRCULARSTRING (1 0,0 1,-1 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)

    ogrtest.check_feature_geometry(
        geom, ogr.CreateGeometryFromWkt("CIRCULARSTRING (2 0,0 2,-2 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)

    ogrtest.check_feature_geometry(
        geom, ogr.CreateGeometryFromWkt("CIRCULARSTRING (1 4,-1 2,1 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)

    ogrtest.check_feature_geometry(
        geom,
        "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))",
    )


###############################################################################
# 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)

    ogrtest.check_feature_geometry(
        geom, ogr.CreateGeometryFromWkt("CIRCULARSTRING (-1 2,3 2,-1 2)")
    )


###############################################################################
# Test GML CircleByCenterPoint with uom="m" and uom="km"


def test_gml_CircleByCenterPoint_srs_geog_uom_m_km():

    gml = '<gml:CircleByCenterPoint srsName="urn:ogc:def:crs:EPSG::4326"><gml:pos>49 2</gml:pos><gml:radius uom="m">2000</gml:radius></gml:CircleByCenterPoint>'
    geom1 = ogr.CreateGeometryFromGML(gml)
    geom1.SwapXY()

    gml = '<gml:CircleByCenterPoint srsName="URN:OGC:DEF:CRS:OGC:1.3:CRS84"><gml:pos>2 49</gml:pos><gml:radius uom="km">2</gml:radius></gml:CircleByCenterPoint>'
    geom2 = ogr.CreateGeometryFromGML(gml)

    ogrtest.check_feature_geometry(geom1, geom2)


###############################################################################
# Test compound curve of ArcByCenterPoint whose ends don't exactly match
# with ends of neighbouring curves, as found in some AIXM files
# with all curves in the same <segment> element as found in #2356)


def test_gml_CompoundCurve_of_ArcByCenterPoint_curve_in_same_segments():

    geom = ogr.CreateGeometryFromGML(
        """
        <aixm:Surface srsName="urn:ogc:def:crs:EPSG::4326" gml:id="ID_249">
            <gml:patches>
                <gml:PolygonPatch>
                    <gml:exterior>
                        <gml:Ring>
                            <gml:curveMember>
                                <gml:Curve gml:id="ID_250">
                                    <gml:segments>
                                        <gml:GeodesicString>
                                            <gml:posList>55.233333333333334
                                            -36.166666666666664 55.23116372807667
                                            -36.89437337916484</gml:posList>
                                        </gml:GeodesicString>
                                        <gml:ArcByCenterPoint numArc="1">
                                            <gml:posList>55.2333333333333
                                            -36.166666666666664</gml:posList>
                                            <gml:radius uom="NM">25.0</gml:radius>
                                            <gml:startAngle uom="deg">270.0</gml:startAngle>
                                            <gml:endAngle uom="deg">497.0</gml:endAngle>
                                        </gml:ArcByCenterPoint>
                                        <gml:GeodesicString>
                                            <gml:posList>54.92816350530716 -35.674116070018954
                                            55.233333333333334
                                            -36.166666666666664</gml:posList>
                                        </gml:GeodesicString>
                                    </gml:segments>
                                </gml:Curve>
                            </gml:curveMember>
                        </gml:Ring>
                    </gml:exterior>
                </gml:PolygonPatch>
            </gml:patches>
            <aixm:horizontalAccuracy uom="KM">2.0</aixm:horizontalAccuracy>
        </aixm:Surface>"""
    )

    ogrtest.check_feature_geometry(
        geom,
        "POLYGON ((55.2333333333333 -36.1666666666667,55.2311637280767 -36.8943733791648,55.2602248071013 -36.8960852160185,55.2891782700249 -36.8912782655051,55.3178697537514 -36.88292675789,55.3461587637071 -36.8710639413776,55.3739064765608 -36.8557405708675,55.4009764350458 -36.8370248014709,55.4272352367262 -36.8150019876212,55.4525532129231 -36.7897743859994,55.476805093957 -36.7614607612323,55.4998706568286 -36.7301958939182,55.5216353514589 -36.6961299915025,55.5419909016414 -36.6594280032268,55.5608358769213 -36.6202688413925,55.5780762317212 -36.5788445119267,55.5936258081681 -36.5353591583435,55.6074067992521 -36.4900280239174,55.6193501691593 -36.4430763379496,55.6293960278662 -36.3947381326996,55.6374939573672 -36.3452549984946,55.6436032872147 -36.2948747851727,55.6476933173936 -36.2438502586493,55.6497434869178 -36.19243772209,55.6497434869178 -36.1408956112433,55.6476933173936 -36.089483074684,55.6436032872147 -36.0384585481606,55.6374939573672 -35.9880783348387,55.6293960278662 -35.9385952006337,55.6193501691593 -35.8902569953837,55.6074067992521 -35.8433053094159,55.5936258081681 -35.7979741749898,55.5780762317212 -35.7544888214066,55.5608358769213 -35.7130644919408,55.5419909016414 -35.6739053301065,55.5216353514589 -35.6372033418322,55.4998706568286 -35.6031374394151,55.476805093957 -35.571872572101,55.4525532129231 -35.5435589473339,55.4272352367262 -35.5183313457121,55.4009764350458 -35.4963085318624,55.3739064765608 -35.4775927624659,55.3461587637071 -35.4622693919557,55.3178697537514 -35.4504065754433,55.2891782700249 -35.4420550678282,55.2602248071013 -35.4372481173149,55.2311508336186 -35.4360014509317,55.2020980963355 -35.4383133491681,55.1732079288891 -35.4441648063421,55.1446205685763 -35.4535197729773,55.1164744843283 -35.4663254761286,55.0889057188812 -35.4825128133848,55.0620472479757 -35.5019968161103,55.0360283592393 -35.524677177381,55.0109740532301 -35.5504388400636,54.9870044689367 -35.5791526404379,54.9642343358562 -35.6106760028906,54.9427724545944 -35.6448536812344,54.9281635053072 -35.674116070019,55.2333333333333 -36.1666666666667))",
    )


###############################################################################
# Test Ring starting with ArcByCenterPoint


def test_gml_Ring_starting_with_ArcByCenterPoint():

    geom = ogr.CreateGeometryFromGML(
        """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns3:Surface xmlns:ns1="http://www.opengis.net/gml/3.2" xmlns:ns2="http://www.w3.org/1999/xlink" xmlns:ns3="http://www.aixm.aero/schema/5.1" xmlns:ns4="http://www.isotc211.org/2005/gco" xmlns:ns5="http://www.isotc211.org/2005/gmd" xmlns:ns6="http://www.isotc211.org/2005/gts" xmlns:ns7="http://www.aixm.aero/schema/5.1/message" srsName="urn:ogc:def:crs:EPSG::4326" ns1:id="Ase_Proj_1561541">
    <ns1:patches>
        <ns1:PolygonPatch>
            <ns1:exterior>
                <ns1:Ring>
                    <ns1:curveMember>
                        <ns1:Curve ns1:id="Ase_Curv_1561541">
                            <ns1:segments>
<ns1:ArcByCenterPoint interpolation="circularArcCenterPointWithRadius" numArc="1">
    <ns1:posList srsName="urn:ogc:def:crs:EPSG::4326">46.5875 0.3066666666666666</ns1:posList>
    <ns1:radius uom="[nmi_i]">9.5</ns1:radius>
    <ns1:startAngle uom="deg">6.295729688631284</ns1:startAngle>
    <ns1:endAngle uom="deg">67.38797951888118</ns1:endAngle>
</ns1:ArcByCenterPoint>
<ns1:GeodesicString interpolation="geodesic">
    <ns1:posList srsName="urn:ogc:def:crs:EPSG::4326">46.64833333333333 0.5194444444444445 46.43861111111111 0.33805555555555555 46.42305555555555 0.28944444444444445</ns1:posList>
</ns1:GeodesicString>
<ns1:ArcByCenterPoint interpolation="circularArcCenterPointWithRadius" numArc="1">
    <ns1:posList srsName="urn:ogc:def:crs:EPSG::4326">46.581388888888895 0.2980555555555556</ns1:posList>
    <ns1:radius uom="[nmi_i]">9.5</ns1:radius>
    <ns1:startAngle uom="deg">-177.84615335400528</ns1:startAngle>
    <ns1:endAngle uom="deg">-120.68835384474265</ns1:endAngle>
</ns1:ArcByCenterPoint>
<ns1:GeodesicString interpolation="geodesic">
    <ns1:posList srsName="urn:ogc:def:crs:EPSG::4326">46.500277777777775 0.10055555555555556 46.54083333333333 0.10555555555555556 46.575 0.225 46.59444444444445 0.25833333333333336 46.65833333333333 0.2833333333333333 46.69555555555555 0.25555555555555554 46.745 0.33194444444444443</ns1:posList>
</ns1:GeodesicString>
                            </ns1:segments>
                        </ns1:Curve>
                    </ns1:curveMember>
                </ns1:Ring>
            </ns1:exterior>
        </ns1:PolygonPatch>
    </ns1:patches>
</ns3:Surface>"""
    )
    # print(g)

    ogrtest.check_feature_geometry(
        geom,
        ogr.CreateGeometryFromWkt(
            "POLYGON ((46.745 0.331944444444444,46.7432764927165 0.347962462754535,46.7409162535525 0.363717281627594,46.7378065348593 0.3791917846605,46.7339626150092 0.394310000163572,46.7294033759096 0.408997750371246,46.7241512079629 0.423183023082575,46.7182318974714 0.436796331344972,46.7116744971061 0.449771059387196,46.7045111801497 0.462043792829896,46.6967770793052 0.473554631563425,46.6885101109471 0.484247483569652,46.6797507857586 0.494070338341013,46.6705420067727 0.502975518511247,46.6609288558889 0.5109199085045,46.6509583699943 0.517865159176619,46.6483333333333 0.519444444444444,46.4386111111111 0.338055555555556,46.4230555555555 0.289444444444444,46.4239652827541 0.273432507330975,46.4255282239253 0.25756088338307,46.4278483647801 0.241884857622964,46.4309144976449 0.226480183207377,46.4347118090807 0.21142133567082,46.4392219496614 0.196781161237034,46.4444231204746 0.18263053185483,46.450290175977 0.169038008752016,46.4567947427662 0.156069515749848,46.4639053537626 0.143788023916768,46.4715875972233 0.132253248900933,46.4798042799442 0.121521362391196,46.4885156039408 0.111644719041597,46.4976793558324 0.102671600158084,46.5002777777778 0.100555555555556,46.5408333333333 0.105555555555556,46.575 0.225,46.5944444444444 0.258333333333333,46.6583333333333 0.283333333333333,46.6955555555556 0.255555555555556,46.745 0.331944444444444))"
        ),
    )


###############################################################################
# Test Ring ending with ArcByCenterPoint


def test_gml_Ring_ending_with_ArcByCenterPoint():

    geom = ogr.CreateGeometryFromGML(
        """<Surface srsName="urn:ogc:def:crs:EPSG::4326" gml:id="SRF15">
  <gml:patches>
    <gml:PolygonPatch>
      <gml:exterior>
        <gml:Ring>
          <gml:curveMember>
            <gml:Curve gml:id="CRV285">
              <gml:segments>
                <gml:GeodesicString>
                  <gml:pos>65.921852847164544 57.491624339427801</gml:pos>
                  <gml:pos>65.994485559282040 57.381695154985898</gml:pos>
                </gml:GeodesicString>
                <gml:GeodesicString>
                  <gml:pos>65.994485559282040 57.381695154985898</gml:pos>
                  <gml:pos>66.005296531715544 57.370309546435649</gml:pos>
                </gml:GeodesicString>
                <gml:GeodesicString>
                  <gml:pos>66.005296531715544 57.370309546435649</gml:pos>
                  <gml:pos>66.016091667389503 57.358930089809121</gml:pos>
                </gml:GeodesicString>
                <gml:GeodesicString>
                  <gml:pos>66.016091667389503 57.358930089809121</gml:pos>
                  <gml:pos>66.098645447810924 57.305543979762817</gml:pos>
                </gml:GeodesicString>
                <gml:ArcByCenterPoint numArc="1">
                  <gml:pos>66.015066666666669 57.356413888888888</gml:pos>
                  <gml:radius uom="[NMI_I]">5.183821647136702</gml:radius>
                  <gml:startAngle uom="DEG">346.133716913420812</gml:startAngle>
                  <gml:endAngle uom="DEG">246.770739243069897</gml:endAngle>
                </gml:ArcByCenterPoint>
                <gml:GeodesicString>
                  <gml:pos>65.980986631402914 57.162257469110280</gml:pos>
                  <gml:pos>65.960397363228381 57.184109890966802</gml:pos>
                </gml:GeodesicString>
                <gml:ArcByCenterPoint numArc="1">
                  <gml:pos>65.994450000000001 57.378138888888891</gml:pos>
                  <gml:radius uom="[NMI_I]">5.183821647136512</gml:radius>
                  <gml:startAngle uom="DEG">246.790586752267330</gml:startAngle>
                  <gml:endAngle uom="DEG">147.427609082272085</gml:endAngle>
                </gml:ArcByCenterPoint>
              </gml:segments>
            </gml:Curve>
          </gml:curveMember>
        </gml:Ring>
      </gml:exterior>
    </gml:PolygonPatch>
  </gml:patches>
</Surface>
"""
    )
    # print(g)

    ogrtest.check_feature_geometry(
        geom,
        ogr.CreateGeometryFromWkt(
            "POLYGON ((65.9218528471645 57.4916243394278,65.994485559282 57.3816951549859,66.0052965317155 57.3703095464356,66.0160916673895 57.3589300898091,66.0986454478109 57.3055439797628,66.0972833787257 57.2909960861013,66.0952275333989 57.2770050871946,66.0927800217659 57.2634046235748,66.0899528791643 57.2502614506486,66.0867600033801 57.2376400142709,66.0832170844948 57.2256021285702,66.079341525797 57.214206668632,66.0751523561957 57.203509279214,66.0706701346179 57.1935621012919,66.0659168469146 57.1844135176486,66.0609157958339 57.1761079188393,66.0556914846553 57.1686854906152,66.0502694951079 57.1621820236802,66.0446763602204 57.1566287467641,66.0389394327704 57.1520521834553,66.033086750019 57.1484740335078,66.0271468954283 57.145911078861,66.0211488580662 57.1443751146804,66.0151218904116 57.1438729053792,66.0090953652666 57.1444061657465,66.0030986324867 57.1459715668484,65.9971608762266 57.1485607664255,65.991310973392 57.1521604634455,65.9855773539744 57.156752476156,65.9809866314029 57.1622574691103,65.9603973632284 57.1841098909668,65.9548299773474 57.1895629087476,65.9495750702849 57.1968227388142,65.9445389220664 57.2049612750665,65.9397459320329 57.2139385813473,65.935219308136 57.2237107308994,65.9309809566457 57.234230023973,65.927051378271 57.2454452217566,65.9234495711475 57.2573017957448,65.9201929411068 57.269742191149,65.9172972196136 57.2827061032052,65.914776389716 57.2961307649312,65.9126426203217 57.3099512454202,65.9109062090733 57.3241007570179,65.9095755340619 57.3385109700802,65.9086570145768 57.353112334239,65.9081550810541 57.3678344048457,65.9080721543467 57.382606172423,65.9084086344011 57.3973563949994,65.9091628983867 57.4120139317594,65.9103313082862 57.4265080751922,65.911908227915 57.4407688820673,65.9138860493003 57.4547275015333,65.9162552283127 57.468316498379,65.9190043294021 57.4814701705531,65.9218528471645 57.4916243394278))"
        ),
    )


###############################################################################
# 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)"
    ogrtest.check_feature_geometry(geom, ogr.CreateGeometryFromWkt(expected_wkt))

    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))"
    ogrtest.check_feature_geometry(geom, ogr.CreateGeometryFromWkt(expected_wkt))


###############################################################################
# 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_one_CircularString():

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

    gml_out = geom.ExportToGML(["FORMAT=GML3"])
    expected_gml = "<gml:Polygon><gml:exterior><gml:Ring><gml:curveMember><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:curveMember></gml:Ring></gml:exterior></gml:Polygon>"
    assert gml_out == expected_gml

    gml_out = geom.ExportToGML(["FORMAT=GML3", "GMLID=gmlid"])
    expected_gml = '<gml:Polygon gml:id="gmlid"><gml:exterior><gml:Ring><gml:curveMember><gml:Curve gml:id="gmlid.exterior"><gml:segments><gml:Circle><gml:posList>0 0 0.5 0.5 1 0</gml:posList></gml:Circle></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior></gml:Polygon>'
    assert gml_out == expected_gml


def test_gml_OGRCurvePolygon_one_CircularString_with_interior_CircularString():

    # Test one CircularString inside one CircularString
    gml = """<gml:Polygon><gml:exterior><gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:Arc><gml:posList>0 0 1 0 0 0</gml:posList></gml:Arc></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior><gml:interior><gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:Arc><gml:posList>0.25 0 0.75 0 0.25 0</gml:posList></gml:Arc></gml:segments></gml:Curve></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))"
    )

    gml_out = geom.ExportToGML(["FORMAT=GML3"])
    expected_gml = "<gml:Polygon><gml:exterior><gml:Ring><gml:curveMember><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:curveMember></gml:Ring></gml:exterior><gml:interior><gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:Circle><gml:posList>0.25 0.0 0.5 0.25 0.75 0.0</gml:posList></gml:Circle></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:interior></gml:Polygon>"
    assert gml_out == expected_gml

    gml_out = geom.ExportToGML(["FORMAT=GML3", "GMLID=gmlid"])
    expected_gml = '<gml:Polygon gml:id="gmlid"><gml:exterior><gml:Ring><gml:curveMember><gml:Curve gml:id="gmlid.exterior"><gml:segments><gml:Circle><gml:posList>0 0 0.5 0.5 1 0</gml:posList></gml:Circle></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior><gml:interior><gml:Ring><gml:curveMember><gml:Curve gml:id="gmlid.interior.0"><gml:segments><gml:Circle><gml:posList>0.25 0.0 0.5 0.25 0.75 0.0</gml:posList></gml:Circle></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:interior></gml:Polygon>'
    assert gml_out == expected_gml


def test_gml_OGRCurvePolygon_CompoundCurve():

    # Test one CompoundCurve with one LineString and on CircularString
    gml = """<gml:Polygon><gml:exterior><gml:Ring><gml:curveMember><gml:LineString><gml:posList>0 -1 0 1</gml:posList></gml:LineString></gml:curveMember><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>0 1 1 0 0 -1</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior></gml:Polygon>"""
    geom = ogr.CreateGeometryFromGML(gml)
    assert (
        geom.ExportToWkt()
        == "CURVEPOLYGON (COMPOUNDCURVE ((0 -1,0 1),CIRCULARSTRING (0 1,1 0,0 -1)))"
    )

    gml_out = geom.ExportToGML(["FORMAT=GML3"])
    assert gml_out == gml

    gml_out = geom.ExportToGML(["FORMAT=GML3", "GMLID=gmlid"])
    expected_gml = '<gml:Polygon gml:id="gmlid"><gml:exterior><gml:Ring><gml:curveMember><gml:LineString gml:id="gmlid.exterior.0"><gml:posList>0 -1 0 1</gml:posList></gml:LineString></gml:curveMember><gml:curveMember><gml:Curve gml:id="gmlid.exterior.1"><gml:segments><gml:ArcString><gml:posList>0 1 1 0 0 -1</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior></gml:Polygon>'
    assert gml_out == expected_gml


def test_gml_OGRCurvePolygon_LinearRing_with_interior_CircularString():

    # 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))"
    )


def test_gml_OGRCurvePolygon_CircularString_with_interior_LinearRing():

    # 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)
    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))",
    )

    gml2 = geom.ExportToGML(["FORMAT=GML3"])
    geom2 = ogr.CreateGeometryFromGML(gml2)
    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)
    ogrtest.check_feature_geometry(geom2, expected_geom2)


###############################################################################
# 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)


###############################################################################
# Test reading geometry from https://github.com/OSGeo/gdal/issues/4155


def test_gml_read_gml_ArcByCenterPoint_projected_crs_northing_easting():

    g = ogr.CreateGeometryFromGML(
        """<gml:Surface srsName="EPSG:2326" srsDimension="2">
    <gml:patches>
    <gml:PolygonPatch>
    <gml:exterior>
    <gml:Ring>
    <gml:curveMember>
    <gml:Curve>
    <gml:segments>
    <gml:LineStringSegment>
    <gml:posList>821502.753690919 838825.332031005 821194.727830006 839043.611480001</gml:posList>
    </gml:LineStringSegment>
    <gml:ArcByCenterPoint numArc="1">
    <gml:posList>821194.396688321 839052.616490606</gml:posList>
    <gml:radius uom="EPSG:2326">9.01109709191771</gml:radius>
    <gml:startAngle uom="degree">177.894008505116</gml:startAngle>
    <gml:endAngle uom="degree">250.98396509322</gml:endAngle>
    </gml:ArcByCenterPoint>
    <gml:LineStringSegment>
    <gml:posList>821185.877350006 839049.680380003 821502.753690919 838825.332031005</gml:posList>
    </gml:LineStringSegment>
    </gml:segments>
    </gml:Curve>
    </gml:curveMember>
    </gml:Ring>
    </gml:exterior>
    </gml:PolygonPatch>
    </gml:patches>
    </gml:Surface>"""
    )
    assert g is not None
