#!/usr/bin/env python
# -*- coding: utf-8 -*-
###############################################################################
# $Id: ogr_geom.py d7e898f6034a9c6c0f83cfbff921434dfc2082be 2018-04-18 23:07:52 +1000 Ben Elliston $
#
# Project:  GDAL/OGR Test Suite
# Purpose:  Test Misc. OGRGeometry operations.
# Author:   Frank Warmerdam <warmerdam@pobox.com>
#
###############################################################################
# Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
# Copyright (c) 2008-2014, Even Rouault <even dot rouault at mines-paris dot org>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
###############################################################################

import math
import pickle
import random
import sys

sys.path.append('../pymod')

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

###############################################################################
# Test Area calculation for a MultiPolygon (which exercises lower level
# get_Area() methods as well).


def ogr_geom_area():

    geom_wkt = 'MULTIPOLYGON( ((0 0,1 1,1 0,0 0)),((0 0,10 0, 10 10, 0 10),(1 1,1 2,2 2,2 1)) )'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)

    area = geom.GetArea()
    if abs(area - 99.5) > 0.00000000001:
        gdaltest.post_reason('GetArea() result wrong, got %g.' % area)
        return 'fail'

    # OGR >= 1.8.0
    area = geom.Area()
    if abs(area - 99.5) > 0.00000000001:
        gdaltest.post_reason('Area() result wrong, got %g.' % area)
        return 'fail'

    return 'success'

###############################################################################
# Test Area calculation for a LinearRing (which exercises special case of
# getGeometryType value).


def ogr_geom_area_linearring():

    geom = ogr.Geometry(type=ogr.wkbLinearRing)
    geom.AddPoint_2D(0, 0)
    geom.AddPoint_2D(10, 0)
    geom.AddPoint_2D(10, 10)
    geom.AddPoint_2D(0, 10)
    geom.AddPoint_2D(0, 0)

    area = geom.GetArea()
    if abs(area - 100.0) > 0.00000000001:
        gdaltest.post_reason('Area result wrong, got %g.' % area)
        return 'fail'

    return 'success'

###############################################################################
# Test Area calculation for a GeometryCollection


def ogr_geom_area_geometrycollection():

    # OGR >= 1.8.0
    geom_wkt = 'GEOMETRYCOLLECTION( POLYGON((0 0,1 1,1 0,0 0)), MULTIPOLYGON(((0 0,1 1,1 0,0 0))), LINESTRING(0 0,1 1), POINT(0 0), GEOMETRYCOLLECTION EMPTY )'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)

    area = geom.Area()
    if abs(area - 1) > 0.00000000001:
        gdaltest.post_reason('Area() result wrong, got %g.' % area)
        return 'fail'

    return 'success'

###############################################################################
# Test Area calculation for a LinearRing whose coordinates are shifted by a
# huge value With algorithm prior to #3556, this would return 0.


def ogr_geom_area_linearring_big_offset():

    geom = ogr.Geometry(type=ogr.wkbLinearRing)
    BIGOFFSET = 1.0e11
    geom.AddPoint_2D(BIGOFFSET + 0, BIGOFFSET + 0)
    geom.AddPoint_2D(BIGOFFSET + 10, BIGOFFSET + 0)
    geom.AddPoint_2D(BIGOFFSET + 10, BIGOFFSET + 10)
    geom.AddPoint_2D(BIGOFFSET + 0, BIGOFFSET + 10)
    geom.AddPoint_2D(BIGOFFSET + 0, BIGOFFSET + 0)

    area = geom.GetArea()
    if abs(area - 100.0) > 0.00000000001:
        gdaltest.post_reason('Area result wrong, got %g.' % area)
        return 'fail'

    return 'success'

###############################################################################
# Test Area calculation for a Triangle


def ogr_geom_area_triangle():

    geom_wkt = 'TRIANGLE((0 0,100 0,0 100,0 0))'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)

    area = geom.GetArea()
    if abs(area - 4999.5) < 0.00000000001:
        gdaltest.post_reason('GetArea() result wrong, got %g.' % area)
        return 'fail'

    # OGR >= 1.8.0
    area = geom.Area()
    if abs(area - 4999.5) < 0.00000000001:
        gdaltest.post_reason('Area() result wrong, got %g.' % area)
        return 'fail'

    return 'success'


def ogr_geom_is_empty():

    geom_wkt = 'LINESTRING EMPTY'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)

    if not geom.IsEmpty():
        gdaltest.post_reason("IsEmpty returning false for an empty geometry")
        return 'fail'

    geom_wkt = 'POINT( 1 2 )'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)
    if not geom:
        gdaltest.post_reason("A geometry could not be created from wkt: %s" % geom_wkt)
        return 'fail'

    if geom.IsEmpty():
        gdaltest.post_reason("IsEmpty returning true for a non-empty geometry")
        return 'fail'
    return 'success'

###############################################################################
# Test if a Triangle is Empty


def ogr_geom_is_empty_triangle():

    geom_wkt = 'TRIANGLE EMPTY'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)

    if not geom.IsEmpty():
        gdaltest.post_reason("IsEmpty returning false for an empty geometry")
        return 'fail'

    geom = ogr.CreateGeometryFromWkb(geom.ExportToWkb())

    if not geom.IsEmpty():
        gdaltest.post_reason("IsEmpty returning false for an empty geometry")
        return 'fail'

    geom_wkt = 'TRIANGLE((0 0,100 0,0 100,0 0))'

    geom = ogr.CreateGeometryFromWkt(geom_wkt)
    if not geom:
        gdaltest.post_reason("A geometry could not be created from wkt: %s" % geom_wkt)
        return 'fail'

    if geom.IsEmpty():
        gdaltest.post_reason("IsEmpty returning true for a non-empty geometry")
        return 'fail'
    return 'success'


def ogr_geom_pickle():
    geom_wkt = 'MULTIPOLYGON( ((0 0,1 1,1 0,0 0)),((0 0,10 0, 10 10, 0 10),(1 1,1 2,2 2,2 1)) )'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)
    p = pickle.dumps(geom)
    with gdaltest.error_handler():
        g = pickle.loads(p)

    if not geom.Equal(g):
        gdaltest.post_reason("pickled geometries were not equal")
        return 'fail'

    return 'success'

###############################################################################
# Test suite for PolyhedralSurface


def ogr_geom_polyhedral_surface():

    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)

    wkb_string = ps.ExportToWkb(ogr.wkbXDR)
    geom = ogr.CreateGeometryFromWkb(wkb_string)
    wkt_string = geom.ExportToWkt()
    if wkt_string != wkt_original:
        gdaltest.post_reason("Failure in Wkb methods of PolyhedralSurface")
        return 'fail'

    wkt_string = geom.Clone().ExportToWkt()
    if wkt_string != wkt_original:
        gdaltest.post_reason("Failure in Clone()")
        return 'fail'

    polygon_wkt = ogr.ForceTo(geom.Clone(), ogr.wkbPolygon).ExportToWkt()
    if polygon_wkt != wkt_original:
        gdaltest.post_reason("fail")
        print(polygon_wkt)
        return 'fail'

    polygon_wkt = ogr.ForceTo(geom.Clone(), ogr.wkbMultiPolygon).ExportToWkt()
    if polygon_wkt != 'MULTIPOLYGON (((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)))':
        gdaltest.post_reason("fail")
        print(polygon_wkt)
        return 'fail'

    if ogrtest.have_sfcgal():
        area = ps.Area()
        if area != 6.0:
            gdaltest.post_reason("Wrong area of PolyhedralSurface")
            return 'fail'

    size = ps.WkbSize()
    if size != 807:
        gdaltest.post_reason("Wrong WkbSize() of PolyhedralSurface")
        return 'fail'

    # if ogrtest.have_sfcgal():
    #    geom = ps.DelaunayTriangulation(0.0,True)
    #    wkt_geom_dt = 'MULTILINESTRING ((0 1 0,1 1 0),(0 0 0,0 1 0),(0 0 0,1 0 0),(1 0 0,1 1 0),(0 1 0,1 0 0))'
    #    wkt_geom = geom.ExportToWkt()
    #    if wkt_geom != wkt_geom_dt:
    #        gdaltest.post_reason ("Failure in DelaunayTriangulation() of PolyhedralSurface")
    #        print(wkt_geom)
    #        return 'fail'

    if ogrtest.have_geos() or ogrtest.have_sfcgal():
        geom = ogr.CreateGeometryFromWkb(wkb_string)
        if not ps.Contains(geom):
            gdaltest.post_reason("Failure in Contains() of PolyhedralSurface")
            return 'fail'

    if ps.IsEmpty():
        gdaltest.post_reason("Failure in IsEmpty() of PolyhedralSurface")
        return 'fail'

    ps.Empty()
    wkt_string = ps.ExportToWkt()
    if wkt_string != 'POLYHEDRALSURFACE Z EMPTY':
        gdaltest.post_reason("Failure in Empty() of PolyhedralSurface")
        return 'fail'

    g = ogr.CreateGeometryFromWkt('POLYHEDRALSURFACE (((0 0 0,0 0 1,0 1 1,0 1 0,0 0 0)))')
    if g.Equals(g) == 0:
        gdaltest.post_reason("fail")
        return 'fail'

    for wkt in ['MULTIPOLYGON (((0 0 0,0 0 1,0 1 1,0 1 0,0 0 0)))',
                'POLYHEDRALSURFACE (((0 0 0,0 0 1,0 1 1,0 0 0)))',
                'POLYHEDRALSURFACE (((0 0 0,0 0 1,0 1 1,0 0 0)),((0 0 0,0 0 1,0 1 1,0 0 0)))',
                'POLYHEDRALSURFACE EMPTY']:
        g2 = ogr.CreateGeometryFromWkt(wkt)
        if g.Equals(g2):
            gdaltest.post_reason("Unexpected true Equals() return")
            print(wkt)
            return 'fail'

    # Error
    if g.AddGeometry(ogr.CreateGeometryFromWkt('POINT (0 0)')) == 0:
        gdaltest.post_reason("fail")
        return 'fail'

    # Error
    if g.AddGeometryDirectly(ogr.CreateGeometryFromWkt('POINT (0 0)')) == 0:
        gdaltest.post_reason("fail")
        return 'fail'

    # Test dimension promotion
    g = ogr.CreateGeometryFromWkt('POLYHEDRALSURFACE EMPTY')
    g.AddGeometryDirectly(ogr.CreateGeometryFromWkt('POLYGON ZM ((0 0 1 2,0 1 1 2,1 1 1 2,0 0 1 2))'))
    g.AddGeometryDirectly(ogr.CreateGeometryFromWkt('POLYGON ((10 10,10 11,11 11,10 10))'))
    wkt = g.ExportToIsoWkt()
    if wkt != 'POLYHEDRALSURFACE ZM (((0 0 1 2,0 1 1 2,1 1 1 2,0 0 1 2)),((10 10 0 0,10 11 0 0,11 11 0 0,10 10 0 0)))':
        gdaltest.post_reason("fail")
        print(wkt)
        return 'fail'

    return 'success'

###############################################################################
# Test suite for TIN


def ogr_geom_tin():
    poly1 = ogr.CreateGeometryFromWkt("TRIANGLE ((0 0 0,0 0 1,0 1 0,0 0 0))")
    poly2 = ogr.CreateGeometryFromWkt("TRIANGLE ((0 0 0,0 1 0,1 1 0,0 0 0))")
    tin = ogr.Geometry(ogr.wkbTIN)
    tin.AddGeometry(poly1)
    tin.AddGeometry(poly2)
    polygon_wkt = [poly1.ExportToWkt(), poly2.ExportToWkt()]
    for i in range(0, tin.GetGeometryCount()):
        geom = tin.GetGeometryRef(i)
        wkt_geom = geom.ExportToWkt()
        if polygon_wkt[i] != wkt_geom:
            gdaltest.post_reason("Failure in getting geometries of TIN")
            return 'fail'

    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)

    wkb_string = tin.ExportToWkb(ogr.wkbXDR)
    geom = ogr.CreateGeometryFromWkb(wkb_string)
    wkt_string = geom.ExportToWkt()
    if wkt_string != wkt_original:
        gdaltest.post_reason("Failure in Wkb methods of TIN")
        return 'fail'

    wkt_string = geom.Clone().ExportToWkt()
    if wkt_string != wkt_original:
        gdaltest.post_reason("Failure in Clone()")
        return 'fail'

    if ogrtest.have_sfcgal():
        area = 12.3 * tin.Area()
        if area != 12.3:
            gdaltest.post_reason("Wrong area of TIN")
            return 'fail'

    size = tin.WkbSize()
    if size != 227:
        gdaltest.post_reason("Wrong WkbSize() of TIN")
        return 'fail'

    # geom = tin.DelaunayTriangulation(0.0,True)
    # wkt_geom_dt = 'MULTILINESTRING ((0 1 0,1 1 0),(0 0 0,0 1 0),(0 0 0,1 1 0))'
    # wkt_geom = geom.ExportToWkt()
    # if wkt_geom != wkt_geom_dt:
    #    gdaltest.post_reason ("Failure in DelaunayTriangulation() of TIN")
    #    print(wkt_geom)
    #    return 'fail'

    # geom = ogr.CreateGeometryFromWkb(wkb_string)
    # if tin.Contains(geom) != True:
    #    gdaltest.post_reason ("Failure in Contains() of TIN")
    #    return 'fail'

    if tin.IsEmpty():
        gdaltest.post_reason("Failure in IsEmpty() of TIN")
        return 'fail'

    tin.Empty()
    wkt_string = tin.ExportToWkt()
    if wkt_string != 'TIN Z EMPTY':
        gdaltest.post_reason("Failure in Empty() of TIN")
        return 'fail'

    wrong_polygon = ogr.CreateGeometryFromWkt('POLYGON ((0 0 0,0 1 0,1 1 0,0 0 1))')
    geom_count = tin.GetGeometryCount()
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    x = tin.AddGeometry(wrong_polygon)
    gdal.PopErrorHandler()
    if tin.GetGeometryCount() != geom_count:
        gdaltest.post_reason("Added wrong geometry in TIN, error has code " + str(x))
        return 'fail'

    if ogrtest.have_geos() or ogrtest.have_sfcgal():
        point = tin.PointOnSurface()
        point_wkt = point.ExportToWkt()
        point_correct_wkt = 'POINT EMPTY'
        if point_wkt != point_correct_wkt:
            gdaltest.post_reason("Wrong Point Obtained for PointOnSurface() in TIN")
            print(point_wkt)
            return 'fail'

    tin = ogr.CreateGeometryFromWkt(wkt_original)
    # point = tin.PointOnSurface()
    # point_wkt = point.ExportToWkt()
    # point_correct_wkt = 'POINT (0.25 0.5)'
    # if point_wkt != point_correct_wkt:
    #    gdaltest.post_reason ("Wrong Point Obtained for PointOnSurface() in TIN")
    #    print(point_wkt)
    #    return 'fail'

    tin.FlattenTo2D()
    if tin.IsValid():
        gdaltest.post_reason("Problem with IsValid() in TIN")
        return 'fail'

    # 4 points
    invalid_wkt = 'TIN (((0 0,0 1,1 1,1 0,0 0)))'
    with gdaltest.error_handler():
        g = ogr.CreateGeometryFromWkt(invalid_wkt)
    if g is not None:
        gdaltest.post_reason('fail')
        return 'fail'

    # hole
    invalid_wkt = 'TIN(((0 0,0 1,1 1,0 0),(0.1 0.1,0.1 0.2,0.2 0.2,0.1 0.1)))'
    with gdaltest.error_handler():
        g = ogr.CreateGeometryFromWkt(invalid_wkt)
    if g is not None:
        gdaltest.post_reason('fail')
        return 'fail'

    invalid_wkt = 'TIN (POLYGON((0 0,0 1,1 1,0 0)))'
    with gdaltest.error_handler():
        g = ogr.CreateGeometryFromWkt(invalid_wkt)
    if g is not None:
        gdaltest.post_reason('fail')
        return 'fail'

    # Add a POLYGON that can be cast as a TRIANGLE
    g = ogr.Geometry(ogr.wkbTIN)
    if g.AddGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 1,1 1,0 0))')) != 0:
        gdaltest.post_reason('fail')
        return 'fail'
    if g.ExportToIsoWkt() != 'TIN (((0 0,0 1,1 1,0 0)))':
        gdaltest.post_reason('fail')
        return 'fail'

    return 'success'

###############################################################################
# Test OGRGeometry::getBoundary() result for point.


def ogr_geom_boundary_point():

    if not ogrtest.have_geos():
        return 'skip'

    geom_wkt = 'POINT(1 1)'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)

    bnd = geom.GetBoundary()
    if bnd.GetGeometryType() != ogr.wkbGeometryCollection:
        gdaltest.post_reason('GetBoundary not reported as GEOMETRYCOLLECTION EMPTY')
        return 'fail'

    bnd = geom.Boundary()
    if bnd.GetGeometryType() != ogr.wkbGeometryCollection:
        gdaltest.post_reason('Boundary not reported as GEOMETRYCOLLECTION EMPTY')
        return 'fail'

    return 'success'

###############################################################################
# Test OGRGeometry::getBoundary() result for multipoint.


def ogr_geom_boundary_multipoint():

    if not ogrtest.have_geos():
        return 'skip'

    geom_wkt = 'MULTIPOINT((0 0),(1 1))'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)

    bnd = geom.GetBoundary()
    if bnd.GetGeometryType() != ogr.wkbGeometryCollection:
        gdaltest.post_reason('Boundary not reported as GEOMETRYCOLLECTION EMPTY')
        return 'fail'

    return 'success'

###############################################################################
# Test OGRGeometry::getBoundary() result for linestring.


def ogr_geom_boundary_linestring():

    if not ogrtest.have_geos():
        return 'skip'

    geom_wkt = 'LINESTRING(0 0, 1 1, 2 2, 3 2, 4 2)'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)

    bnd = geom.GetBoundary()
    if bnd.GetGeometryType() != ogr.wkbMultiPoint:
        gdaltest.post_reason('Boundary not reported as MULTIPOINT')
        print(bnd)
        return 'fail'

    if bnd.GetGeometryCount() != 2:
        gdaltest.post_reason('Boundary not reported as MULTIPOINT consisting of 2 points')
        return 'fail'

    geom_wkt = 'LINESTRING(0 0, 1 0, 1 1, 0 1, 0 0)'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)

    bnd = geom.GetBoundary()
    if bnd.GetGeometryType() != ogr.wkbMultiPoint:
        gdaltest.post_reason('Boundary not reported as MULTIPOINT')
        return 'fail'

    if bnd.GetGeometryCount() != 0:
        gdaltest.post_reason('Boundary not reported as MULTIPOINT EMPTY')
        return 'fail'

    return 'success'

###############################################################################
# Test OGRGeometry::getBoundary() result for polygon.


def ogr_geom_boundary_polygon():

    if not ogrtest.have_geos():
        return 'skip'

    geom_wkt = 'POLYGON((0 0,1 1,1 0,0 0))'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)

    bnd = geom.GetBoundary()
    if bnd.GetGeometryType() != ogr.wkbLineString:
        gdaltest.post_reason('Boundary not reported as non-empty LINESTRING')
        print(bnd)
        return 'fail'

    return 'success'

###############################################################################
# Test OGRBuildPolygonFromEdges() on a geometry collection of line strings


def ogr_geom_build_from_edges_1():

    if not ogrtest.have_geos():
        return 'skip'

    link_coll = ogr.Geometry(type=ogr.wkbGeometryCollection)

    wkt_array = [
        'LINESTRING (-87.601595 30.999522,-87.599623 31.000059,-87.599219 31.00017)',
        'LINESTRING (-87.601595 30.999522,-87.604349 30.999493,-87.606935 30.99952)',
        'LINESTRING (-87.59966 31.000756,-87.599851 31.000805,-87.599992 31.000805,-87.600215 31.000761,-87.600279 31.000723,-87.600586 31.000624,-87.601256 31.000508,-87.602501 31.000447,-87.602801 31.000469,-87.603108 31.000579,-87.603331 31.000716,-87.603523 31.000909,-87.603766 31.001233,-87.603913 31.00136)',
        'LINESTRING (-87.606134 31.000182,-87.605885 31.000325,-87.605343 31.000716,-87.60466 31.001117,-87.604468 31.0012,-87.603913 31.00136)',
        'LINESTRING (-87.599219 31.00017,-87.599289 31.0003,-87.599398 31.000426,-87.599564 31.000547,-87.599609 31.000701,-87.59966 31.000756)',
        'LINESTRING (-87.606935 30.99952,-87.606713 30.999799,-87.6064 30.999981,-87.606134 31.000182)']

    for wkt in wkt_array:
        geom = ogr.CreateGeometryFromWkt(wkt)
        # print "geom is",geom
        link_coll.AddGeometry(geom)

    try:
        poly = ogr.BuildPolygonFromEdges(link_coll)
        if poly is None:
            return 'fail'
    except:
        return 'fail'

    return 'success'

###############################################################################
# Test OGRBuildPolygonFromEdges() on a multilinestring


def ogr_geom_build_from_edges_2():

    if not ogrtest.have_geos():
        return 'skip'

    link_coll = ogr.Geometry(type=ogr.wkbMultiLineString)

    wkt_array = [
        'LINESTRING (-87.601595 30.999522,-87.599623 31.000059,-87.599219 31.00017)',
        'LINESTRING (-87.601595 30.999522,-87.604349 30.999493,-87.606935 30.99952)',
        'LINESTRING (-87.59966 31.000756,-87.599851 31.000805,-87.599992 31.000805,-87.600215 31.000761,-87.600279 31.000723,-87.600586 31.000624,-87.601256 31.000508,-87.602501 31.000447,-87.602801 31.000469,-87.603108 31.000579,-87.603331 31.000716,-87.603523 31.000909,-87.603766 31.001233,-87.603913 31.00136)',
        'LINESTRING (-87.606134 31.000182,-87.605885 31.000325,-87.605343 31.000716,-87.60466 31.001117,-87.604468 31.0012,-87.603913 31.00136)',
        'LINESTRING (-87.599219 31.00017,-87.599289 31.0003,-87.599398 31.000426,-87.599564 31.000547,-87.599609 31.000701,-87.59966 31.000756)',
        'LINESTRING (-87.606935 30.99952,-87.606713 30.999799,-87.6064 30.999981,-87.606134 31.000182)']

    for wkt in wkt_array:
        geom = ogr.CreateGeometryFromWkt(wkt)
        link_coll.AddGeometry(geom)

    try:
        poly = ogr.BuildPolygonFromEdges(link_coll)
        if poly is None:
            return 'fail'
    except:
        return 'fail'

    return 'success'

###############################################################################
# Test OGRBuildPolygonFromEdges() on invalid geometries


def ogr_geom_build_from_edges_3():

    if not ogrtest.have_geos():
        return 'skip'

    src_geom = ogr.CreateGeometryFromWkt('POINT (0 1)')
    try:
        gdal.PushErrorHandler('CPLQuietErrorHandler')
        poly = ogr.BuildPolygonFromEdges(src_geom)
        gdal.PopErrorHandler()
        if poly is not None:
            return 'fail'
    except:
        pass

    src_geom = ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION (LINESTRING(0 1,2 3),POINT(0 1),LINESTRING(0 1,-2 3),LINESTRING(-2 3,2 3))')
    try:
        gdal.PushErrorHandler('CPLQuietErrorHandler')
        poly = ogr.BuildPolygonFromEdges(src_geom)
        gdal.PopErrorHandler()
        if poly is not None:
            return 'fail'
    except:
        pass

    return 'success'

###############################################################################
# Test OGRBuildPolygonFromEdges() and identify exterior ring (#3610)


def ogr_geom_build_from_edges_4():

    if int(gdal.VersionInfo('VERSION_NUM')) < 1900:
        gdaltest.post_reason('would crash')
        return 'skip'

    if not ogrtest.have_geos():
        return 'skip'

    link_coll = ogr.Geometry(type=ogr.wkbGeometryCollection)

    wkt_array = [
        'LINESTRING EMPTY',
        'LINESTRING (1 1,1 2)',
        'LINESTRING EMPTY',
        'LINESTRING (1 2,2 2)',
        'LINESTRING (2 2,2 1)',
        'LINESTRING (2 1,1 1)',
        'LINESTRING (0 0,0 10)',
        'LINESTRING (0 10,10 10)',
        'LINESTRING (10 10,10 0)',
        'LINESTRING (10 0,0 0)'
    ]

    for wkt in wkt_array:
        geom = ogr.CreateGeometryFromWkt(wkt)
        # print "geom is",geom
        link_coll.AddGeometry(geom)

    try:
        poly = ogr.BuildPolygonFromEdges(link_coll)
        if poly is None:
            return 'fail'
        wkt = poly.ExportToWkt()
        if wkt != 'POLYGON ((0 0,0 10,10 10,10 0,0 0),(1 1,1 2,2 2,2 1,1 1))':
            print(wkt)
            return 'fail'
    except:
        return 'fail'

    return 'success'

###############################################################################
# Test GetArea() on empty linear ring (#2792)


def ogr_geom_area_empty_linearring():

    geom = ogr.Geometry(type=ogr.wkbLinearRing)

    area = geom.GetArea()
    if area != 0:
        return 'fail'

    return 'success'

###############################################################################
# Test TransformTo()


def ogr_geom_transform_to():

    # Somewhere in Paris suburbs...
    geom = ogr.CreateGeometryFromWkt('POINT(2 49)')

    # Input SRS is EPSG:4326
    sr = osr.SpatialReference()
    sr.ImportFromEPSG(4326)
    geom.AssignSpatialReference(sr)

    # Output SRS is EPSG:32631
    sr2 = osr.SpatialReference()
    sr2.ImportFromEPSG(32631)
    ret = geom.TransformTo(sr2)

    if ret != 0 or abs(geom.GetX() - 426857) > 1 or abs(geom.GetY() - 5427937) > 1:
        gdaltest.post_reason('failure')
        print(geom.ExportToWkt())
        return 'fail'

    # Geometry without SRS
    geom = ogr.CreateGeometryFromWkt('POINT(2 49)')
    gdal.ErrorReset()
    with gdaltest.error_handler():
        ret = geom.TransformTo(sr2)
    if ret == 0 or gdal.GetLastErrorMsg() == '':
        gdaltest.post_reason('failure')
        return 'fail'

    return 'success'

###############################################################################
# Test Transform()


def ogr_geom_transform():

    # Somewhere in Paris suburbs...
    geom = ogr.CreateGeometryFromWkt('POINT(2 49)')

    # Input SRS is EPSG:4326
    sr = osr.SpatialReference()
    sr.ImportFromEPSG(4326)

    # Output SRS is EPSG:32631
    sr2 = osr.SpatialReference()
    sr2.ImportFromEPSG(32631)

    ct = osr.CoordinateTransformation(sr, sr2)

    geom.Transform(ct)

    if abs(geom.GetX() - 426857) > 1 or abs(geom.GetY() - 5427937) > 1:
        print(geom.ExportToWkt())
        return 'fail'

    return 'success'

###############################################################################
# Test CloseRings()


def ogr_geom_closerings():

    geom = ogr.CreateGeometryFromWkt('POLYGON((0 0,0 1,1 1,1 0))')
    geom.CloseRings()

    if geom.ExportToWkt() != 'POLYGON ((0 0,0 1,1 1,1 0,0 0))':
        print(geom.ExportToWkt())
        return 'fail'

    geom.CloseRings()
    if geom.ExportToWkt() != 'POLYGON ((0 0,0 1,1 1,1 0,0 0))':
        print(geom.ExportToWkt())
        return 'fail'

    return 'success'

###############################################################################
# Test Segmentize()


def ogr_geom_segmentize():

    geom = ogr.CreateGeometryFromWkt('LINESTRING(0 0,0 10)')
    geom.Segmentize(1.00001)

    if geom.ExportToWkt() != 'LINESTRING (0 0,0 1,0 2,0 3,0 4,0 5,0 6,0 7,0 8,0 9,0 10)':
        print(geom.ExportToWkt())
        return 'fail'

    geom = ogr.CreateGeometryFromWkt('LINESTRING(0 0 1,0 10 1)')
    geom.Segmentize(1.00001)

    if geom.ExportToWkt() != 'LINESTRING (0 0 1,0 1 1,0 2 1,0 3 1,0 4 1,0 5 1,0 6 1,0 7 1,0 8 1,0 9 1,0 10 1)':
        print(geom.ExportToWkt())
        return 'fail'

    # Check segmentize symmetry : do exact binary comparison.
    in_wkt = 'LINESTRING (0 0,1.2 1,2 0)'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    g1.Segmentize(0.25)
    in_wkt = 'LINESTRING (2 0,1.2 1,0 0)'
    g2 = ogr.CreateGeometryFromWkt(in_wkt)
    g2.Segmentize(0.25)
    for i in range(g1.GetPointCount()):
        if g1.GetPoint(i) != g2.GetPoint(g1.GetPointCount() - 1 - i):
            gdaltest.post_reason('fail')
            print(i)
            print('%.18g' % (g1.GetPoint(i)[0] - g2.GetPoint(g1.GetPointCount() - 1 - i)[0]))
            print('%.18g' % (g1.GetPoint(i)[1] - g2.GetPoint(g1.GetPointCount() - 1 - i)[1]))
            print(g1)
            print(g2)
            return 'fail'

    return 'success'

###############################################################################
# Test Value()


def ogr_geom_value():

    geom = ogr.CreateGeometryFromWkt('LINESTRING(2 3,5 3,5 0)')

    p = geom.Value(-1e-3)
    expected_p = ogr.CreateGeometryFromWkt('POINT (2 3)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    p = geom.Value(geom.Length() / 4)
    expected_p = ogr.CreateGeometryFromWkt('POINT (3.5 3)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    p = geom.Value(geom.Length() / 2)
    expected_p = ogr.CreateGeometryFromWkt('POINT (5 3)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    p = geom.Value(3 * geom.Length() / 4)
    expected_p = ogr.CreateGeometryFromWkt('POINT (5 1.5)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    p = geom.Value(geom.Length() + 1e-3)
    expected_p = ogr.CreateGeometryFromWkt('POINT (5 0)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    return 'success'

###############################################################################
# Test FlattenTo2D(), GetDimension() and GetCoordinateDimension()


def ogr_geom_flattenTo2D():

    geom = ogr.CreateGeometryFromWkt('POINT (1 2 3)')

    # Point is 0 dimension, LineString 1, ...
    if geom.GetDimension() != 0:
        gdaltest.post_reason('fail')
        print(geom.GetDimension())
        return 'fail'

    if geom.GetCoordinateDimension() != 3:
        gdaltest.post_reason('fail')
        print(geom.GetCoordinateDimension())
        return 'fail'

    geom.FlattenTo2D()
    if geom.GetCoordinateDimension() != 2:
        gdaltest.post_reason('fail')
        print(geom.GetCoordinateDimension())
        return 'fail'

    if geom.ExportToWkt() != 'POINT (1 2)':
        gdaltest.post_reason('fail')
        print(geom.ExportToWkt())
        return 'fail'

    return 'success'

###############################################################################
# Test FlattenTo2D(), GetDimension() and GetCoordinateDimension() for Triangle


def ogr_geom_flattenTo2D_triangle():

    geom = ogr.CreateGeometryFromWkt('TRIANGLE ((0 0 0,100 0 100,0 100 100,0 0 0))')

    # Point is 0 dimension, LineString 1, ...
    if geom.GetDimension() != 2:
        gdaltest.post_reason('fail')
        print(geom.GetDimension())
        return 'fail'

    if geom.GetCoordinateDimension() != 3:
        gdaltest.post_reason('fail')
        print(geom.GetCoordinateDimension())
        return 'fail'

    geom.FlattenTo2D()
    if geom.GetCoordinateDimension() != 2:
        gdaltest.post_reason('fail')
        print(geom.GetCoordinateDimension())
        return 'fail'

    if geom.ExportToWkt() != 'TRIANGLE ((0 0,100 0,0 100,0 0))':
        gdaltest.post_reason('fail')
        print(geom.ExportToWkt())
        return 'fail'

    return 'success'

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


def ogr_geom_linestring_limits():

    geom = ogr.CreateGeometryFromWkt('LINESTRING EMPTY')
    if geom.Length() != 0:
        return 'fail'

    gdal.ErrorReset()
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    geom.GetPoint(-1)
    gdal.PopErrorHandler()
    if gdal.GetLastErrorType() == 0:
        return 'fail'

    gdal.ErrorReset()
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    geom.GetPoint(0)
    gdal.PopErrorHandler()
    if gdal.GetLastErrorType() == 0:
        return 'fail'

    gdal.ErrorReset()
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    geom.GetPoint_2D(-1)
    gdal.PopErrorHandler()
    if gdal.GetLastErrorType() == 0:
        return 'fail'

    gdal.ErrorReset()
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    geom.GetPoint_2D(0)
    gdal.PopErrorHandler()
    if gdal.GetLastErrorType() == 0:
        return 'fail'

    gdal.ErrorReset()
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    geom.SetPoint(-1, 5, 6, 7)
    gdal.PopErrorHandler()
    if gdal.GetLastErrorType() == 0:
        return 'fail'

    gdal.ErrorReset()
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    geom.SetPoint_2D(-1, 5, 6)
    gdal.PopErrorHandler()
    if gdal.GetLastErrorType() == 0:
        return 'fail'

    if False:
        gdal.ErrorReset()
        gdal.PushErrorHandler('CPLQuietErrorHandler')
        geom.SetPoint(2147000000, 5, 6, 7)
        gdal.PopErrorHandler()
        if gdal.GetLastErrorType() == 0:
            return 'fail'

        gdal.ErrorReset()
        gdal.PushErrorHandler('CPLQuietErrorHandler')
        geom.SetPoint_2D(2147000000, 5, 6)
        gdal.PopErrorHandler()
        if gdal.GetLastErrorType() == 0:
            return 'fail'

    geom = ogr.CreateGeometryFromWkt('LINESTRING(0 0)')
    if geom.Length() != 0:
        return 'fail'
    geom = ogr.CreateGeometryFromWkt('LINESTRING(0 0, 1 0)')
    if geom.Length() != 1:
        return 'fail'

    return 'success'

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


def ogr_geom_coord_round():

    geom = ogr.CreateGeometryFromWkt('POINT(370441.860 5591000.590)')
    wkt = geom.ExportToWkt()
    if wkt != 'POINT (370441.86 5591000.59)':
        gdaltest.post_reason('did not get expected WKT')
        print(wkt)
        return 'fail'

    return 'success'

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


def ogr_geom_coord_round_2():

    geom = ogr.CreateGeometryFromWkt('POINT(1.0 169.600374)')
    wkt = geom.ExportToWkt()
    if wkt != 'POINT (1.0 169.600374)':
        gdaltest.post_reason('did not get expected WKT')
        print(wkt)
        return 'fail'

    return 'success'

###############################################################################
# Test Area calculation for a Point


def ogr_geom_area_point():

    geom_wkt = 'POINT(0 0)'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)

    with gdaltest.error_handler():
        area = geom.Area()
    if area != 0:
        gdaltest.post_reason('Area() result wrong, got %g.' % area)
        return 'fail'

    return 'success'

###############################################################################
# Test Length calculation for a Point


def ogr_geom_length_point():

    # OGR >= 1.8.0
    geom_wkt = 'POINT(0 0)'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)

    with gdaltest.error_handler():
        length = geom.Length()
    if length != 0:
        gdaltest.post_reason('Length() result wrong, got %g.' % length)
        return 'fail'

    return 'success'

###############################################################################
# Test Length calculation for a MultiLineString


def ogr_geom_length_multilinestring():

    # OGR >= 1.8.0
    geom_wkt = 'MULTILINESTRING((0 0,0 1),(0 0,0 1))'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)

    length = geom.Length()
    if abs(length - 2) > 0.00000000001:
        gdaltest.post_reason('Length() result wrong, got %g.' % length)
        return 'fail'

    return 'success'

###############################################################################
# Test Length calculation for a GeometryCollection


def ogr_geom_length_geometrycollection():

    # OGR >= 1.8.0
    geom_wkt = 'GEOMETRYCOLLECTION( POLYGON((0 0,0 1,1 1,1 0,0 0)), MULTILINESTRING((0 0,0 1),(0 0,0 1)), LINESTRING(0 0,0 1), LINESTRING(0 0,0 1), POINT(0 0), GEOMETRYCOLLECTION EMPTY )'
    geom = ogr.CreateGeometryFromWkt(geom_wkt)

    length = geom.Length()
    if abs(length - 4) > 0.00000000001:
        gdaltest.post_reason('Length() result wrong, got %g.' % length)
        return 'fail'

    return 'success'

###############################################################################
# Test Geometry.GetPoints() (#4016)


def ogr_geom_getpoints():

    geom = ogr.CreateGeometryFromWkt('LINESTRING(0 1,2 3)')
    points = geom.GetPoints()
    if points != [(0.0, 1.0), (2.0, 3.0)]:
        gdaltest.post_reason('did not get expected points (1)')
        print(points)
        return 'fail'
    points = geom.GetPoints(nCoordDimension=3)
    if points != [(0.0, 1.0, 0.0), (2.0, 3.0, 0.0)]:
        gdaltest.post_reason('did not get expected points (2)')
        print(points)
        return 'fail'

    geom = ogr.CreateGeometryFromWkt('LINESTRING(0 1 2,3 4 5)')
    points = geom.GetPoints()
    if points != [(0.0, 1.0, 2.0), (3.0, 4.0, 5.0)]:
        gdaltest.post_reason('did not get expected points (3)')
        print(points)
        return 'fail'
    points = geom.GetPoints(nCoordDimension=2)
    if points != [(0.0, 1.0), (3.0, 4.0)]:
        gdaltest.post_reason('did not get expected points (4)')
        print(points)
        return 'fail'

    geom = ogr.CreateGeometryFromWkt('POINT(0 1)')
    points = geom.GetPoints()
    if points != [(0.0, 1.0)]:
        gdaltest.post_reason('did not get expected points (5)')
        print(points)
        return 'fail'
    points = geom.GetPoints(nCoordDimension=3)
    if points != [(0.0, 1.0, 0.0)]:
        gdaltest.post_reason('did not get expected points (6)')
        print(points)
        return 'fail'

    geom = ogr.CreateGeometryFromWkt('POINT(0 1 2)')
    points = geom.GetPoints()
    if points != [(0.0, 1.0, 2.0)]:
        gdaltest.post_reason('did not get expected points (7)')
        print(points)
        return 'fail'
    points = geom.GetPoints(nCoordDimension=2)
    if points != [(0.0, 1.0)]:
        gdaltest.post_reason('did not get expected points (8)')
        print(points)
        return 'fail'

    return 'success'

###############################################################################
# Test OGRGeometry::empty()


def ogr_geom_empty():

    g1 = ogr.CreateGeometryFromWkt('POLYGON((0 0,1 1,1 2,1 1,0 0))')
    g1.Empty()
    wkt = g1.ExportToWkt()

    if wkt != 'POLYGON EMPTY':
        return 'fail'

    return 'success'

###############################################################################
# Test OGRGeometry::empty() for Triangle


def ogr_geom_empty_triangle():

    g1 = ogr.CreateGeometryFromWkt('TRIANGLE ((0 0,100 0,0 100,0 0))')
    g1.Empty()
    wkt = g1.ExportToWkt()

    if wkt != 'TRIANGLE EMPTY':
        return 'fail'

    return 'success'

###############################################################################
# Test parsing WKT made of 2D and 3D parts


def ogr_geom_mixed_coordinate_dimension():

    # first part is 3D, second part is 2D of same length
    wkt = 'MULTIPOLYGON (((1 2 -4,1 3 -3,2 3 -3,2 2 -3,1 2 -6)),((-1 -2,-1 -3,-2 -3,-2 -2,-1 -2,50 60)))'
    expected_wkt = 'MULTIPOLYGON (((1 2 -4,1 3 -3,2 3 -3,2 2 -3,1 2 -6)),((-1 -2 0,-1 -3 0,-2 -3 0,-2 -2 0,-1 -2 0,50 60 0)))'
    g = ogr.CreateGeometryFromWkt(wkt)
    got_wkt = g.ExportToWkt()
    if got_wkt != expected_wkt:
        gdaltest.post_reason('for %s: got %s, expected %s' % (wkt, got_wkt, expected_wkt))
        return 'fail'

    # first part is 3D, second part is 2D of same length, except the last point which is 3D
    wkt = 'MULTIPOLYGON (((1 2 -4,1 3 -3,2 3 -3,2 2 -3,1 2 -6)),((-1 -2,-1 -3,-2 -3,-2 -2,-1 -2,50 60 7)))'
    expected_wkt = 'MULTIPOLYGON (((1 2 -4,1 3 -3,2 3 -3,2 2 -3,1 2 -6)),((-1 -2 0,-1 -3 0,-2 -3 0,-2 -2 0,-1 -2 0,50 60 7)))'
    g = ogr.CreateGeometryFromWkt(wkt)
    got_wkt = g.ExportToWkt()
    if got_wkt != expected_wkt:
        gdaltest.post_reason('for %s: got %s, expected %s' % (wkt, got_wkt, expected_wkt))
        return 'fail'

    return 'success'

###############################################################################
# Test GetEnvelope3D()


def ogr_geom_getenvelope3d():

    g = ogr.CreateGeometryFromWkt('POINT EMPTY')
    envelope = g.GetEnvelope3D()
    expected_envelope = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
    if envelope != expected_envelope:
        gdaltest.post_reason('did not get expected envelope (1)')
        print(envelope)
        print(expected_envelope)
        return 'fail'

    g = ogr.CreateGeometryFromWkt('POINT(1 2)')
    envelope = g.GetEnvelope3D()
    expected_envelope = (1.0, 1.0, 2.0, 2.0, 0.0, 0.0)
    if envelope != expected_envelope:
        gdaltest.post_reason('did not get expected envelope (2)')
        print(envelope)
        print(expected_envelope)
        return 'fail'

    g = ogr.CreateGeometryFromWkt('POINT(1 2 3)')
    envelope = g.GetEnvelope3D()
    expected_envelope = (1.0, 1.0, 2.0, 2.0, 3.0, 3.0)
    if envelope != expected_envelope:
        gdaltest.post_reason('did not get expected envelope (3)')
        print(envelope)
        print(expected_envelope)
        return 'fail'

    g = ogr.CreateGeometryFromWkt('POLYGON EMPTY')
    envelope = g.GetEnvelope3D()
    expected_envelope = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
    if envelope != expected_envelope:
        gdaltest.post_reason('did not get expected envelope (4)')
        print(envelope)
        print(expected_envelope)
        return 'fail'

    g = ogr.CreateGeometryFromWkt('LINESTRING(1 2,3 4)')
    envelope = g.GetEnvelope3D()
    expected_envelope = (1, 3, 2, 4, 0, 0)
    if envelope != expected_envelope:
        gdaltest.post_reason('did not get expected envelope (5)')
        print(envelope)
        print(expected_envelope)
        return 'fail'

    g = ogr.CreateGeometryFromWkt('MULTIPOLYGON(((1 2 3,-1 2 3,-1 -2 3,-1 2 3,1 2 3),(0.1 0.2 0.3,-0.1 0.2 0.3,-0.1 -0.2 0.3,-0.1 0.2 0.3,0.1 0.2 0.3)),((10 20 -30,-10 20 -30,-10 -20 -30,-10 20 -30,10 20 -30)))')
    envelope = g.GetEnvelope3D()
    expected_envelope = (-10, 10, -20, 20, -30, 3.0)
    if envelope != expected_envelope:
        gdaltest.post_reason('did not get expected envelope (6)')
        print(envelope)
        print(expected_envelope)
        return 'fail'

    g = ogr.CreateGeometryFromWkt('MULTIPOLYGON EMPTY')
    envelope = g.GetEnvelope3D()
    expected_envelope = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
    if envelope != expected_envelope:
        gdaltest.post_reason('did not get expected envelope (7)')
        print(envelope)
        print(expected_envelope)
        return 'fail'

    g = ogr.CreateGeometryFromWkt('TRIANGLE ((0 0 0,100 0 100,0 100 100,0 0 0))')
    envelope = g.GetEnvelope3D()
    expected_envelope = (0.0, 100.0, 0.0, 100.0, 0.0, 100.0)
    if envelope != expected_envelope:
        gdaltest.post_reason('did not get expected envelope (8)')
        print(envelope)
        print(expected_envelope)
        return 'fail'

    return 'success'

###############################################################################
# Test importing/exporting XXX Z EMPTY


def ogr_geom_z_empty():

    for geom in ['POINT', 'LINESTRING', 'POLYGON', 'MULTIPOINT', 'MULTILINESTRING',
                 'MULTIPOLYGON', 'GEOMETRYCOLLECTION', 'CIRCULARSTRING', 'COMPOUNDCURVE',
                 'CURVEPOLYGON', 'MULTICURVE', 'MULTISURFACE']:
        in_wkt = geom + ' Z EMPTY'
        g1 = ogr.CreateGeometryFromWkt(in_wkt)
        out_wkt = g1.ExportToIsoWkt()
        if in_wkt != out_wkt:
            gdaltest.post_reason('fail')
            print(out_wkt)
            return 'fail'

        g2 = ogr.CreateGeometryFromWkb(g1.ExportToIsoWkb())
        out_wkt = g2.ExportToIsoWkt()
        if in_wkt != out_wkt:
            gdaltest.post_reason('fail')
            print(out_wkt)
            return 'fail'

    return 'success'

###############################################################################
# Test HasCurveGeometry and GetLinearGeometry


def ogr_geom_getlineargeometry():

    for geom in ['POINT', 'LINESTRING', 'POLYGON', 'MULTIPOINT', 'MULTILINESTRING',
                 'MULTIPOLYGON', 'GEOMETRYCOLLECTION',
                 ('CIRCULARSTRING', 'LINESTRING'),
                 ('COMPOUNDCURVE', 'LINESTRING'),
                 ('CURVEPOLYGON', 'POLYGON'),
                 ('MULTICURVE', 'MULTILINESTRING'),
                 ('MULTISURFACE', 'MULTIPOLYGON')]:
        try:
            (geom_in, geom_out) = geom
        except:
            geom_in = geom_out = geom
        in_wkt = geom_in + ' EMPTY'
        g = ogr.CreateGeometryFromWkt(in_wkt)
        g2 = g.GetLinearGeometry()
        if geom_in != geom_out and not g.HasCurveGeometry():
            gdaltest.post_reason('fail')
            print(g)
            return 'fail'
        if g2.ExportToWkt() != geom_out + ' EMPTY':
            gdaltest.post_reason('fail')
            print(g)
            print(g2)
            return 'fail'

    g = ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION(POINT (0 1))')
    if g.HasCurveGeometry():
        gdaltest.post_reason('fail')
        return 'fail'
    if g.HasCurveGeometry(True):
        gdaltest.post_reason('fail')
        return 'fail'

    g = ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION(CIRCULARSTRING (0 0,0 1,0 0))')
    if not g.HasCurveGeometry():
        gdaltest.post_reason('fail')
        return 'fail'
    if not g.HasCurveGeometry(True):
        gdaltest.post_reason('fail')
        return 'fail'

    return 'success'

###############################################################################
# Test GetDimension()


def ogr_geom_getdimension():
    for (geom, dim) in [('POINT EMPTY', 0),
                        ('LINESTRING EMPTY', 1),
                        ('POLYGON EMPTY', 2),
                        ('MULTIPOINT EMPTY', 0),
                        ('MULTILINESTRING EMPTY', 1),
                        ('MULTIPOLYGON EMPTY', 2),
                        ('GEOMETRYCOLLECTION EMPTY', 0),
                        ('CIRCULARSTRING EMPTY', 1),
                        ('COMPOUNDCURVE EMPTY', 1),
                        ('CURVEPOLYGON EMPTY', 2),
                        ('MULTICURVE EMPTY', 1),
                        ('TRIANGLE EMPTY', 2),
                        ('MULTISURFACE EMPTY', 2),
                        ('POLYHEDRALSURFACE EMPTY', 2),
                        ('TIN EMPTY', 2)]:
        g = ogr.CreateGeometryFromWkt(geom)
        if g.GetDimension() != dim:
            gdaltest.post_reason('fail')
            print(g)
            print(dim)
            return 'fail'

    g = ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION(LINESTRING EMPTY, POINT (0 1))')
    if g.GetDimension() != 1:
        gdaltest.post_reason('fail')
        return 'fail'

    g = ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION(POINT (0 1), LINESTRING EMPTY, POLYGON EMPTY)')
    if g.GetDimension() != 2:
        gdaltest.post_reason('fail')
        return 'fail'

    return 'success'

###############################################################################
# Test triangle


def ogr_geom_triangle():

    wkt_original = 'TRIANGLE ((0 0,0 1,1 1,0 0))'
    geom = ogr.CreateGeometryFromWkt(wkt_original)

    wkb_string = geom.ExportToWkb(ogr.wkbXDR)
    geom = ogr.CreateGeometryFromWkb(wkb_string)
    wkt_string = geom.ExportToWkt()
    if wkt_string != wkt_original:
        gdaltest.post_reason("Failure in Wkb methods of Triangle")
        return 'fail'

    wkt_string = geom.Clone().ExportToWkt()
    if wkt_string != wkt_original:
        gdaltest.post_reason("Failure in Clone()")
        return 'fail'

    polygon_wkt = ogr.ForceTo(geom.Clone(), ogr.wkbPolygon).ExportToWkt()
    if polygon_wkt != 'POLYGON ((0 0,0 1,1 1,0 0))':
        gdaltest.post_reason("fail")
        print(polygon_wkt)
        return 'fail'

    polygon_wkt = ogr.ForceTo(geom.Clone(), ogr.wkbMultiPolygon).ExportToWkt()
    if polygon_wkt != 'MULTIPOLYGON (((0 0,0 1,1 1,0 0)))':
        gdaltest.post_reason("fail")
        print(polygon_wkt)
        return 'fail'

    return 'success'

###############################################################################
# Test importing invalid triangle WKT


def ogr_geom_triangle_invalid_wkt():

    geom_wkt = 'TRIANGLE (0 0)'
    with gdaltest.error_handler():
        geom = ogr.CreateGeometryFromWkt(geom_wkt)
    if geom is not None:
        gdaltest.post_reason('fail')
        return 'fail'

    geom_wkt = 'TRIANGLE ((0 0))'
    with gdaltest.error_handler():
        geom = ogr.CreateGeometryFromWkt(geom_wkt)
    if geom is not None:
        gdaltest.post_reason('fail')
        print(geom)
        return 'fail'

    geom_wkt = 'TRIANGLE ((0 0,0 1,1 1,1 0))'
    with gdaltest.error_handler():
        geom = ogr.CreateGeometryFromWkt(geom_wkt)
    if geom is not None:
        gdaltest.post_reason('fail')
        print(geom)
        return 'fail'

    geom_wkt = 'TRIANGLE ((0 0,0 1,1 1,1 0,0 0))'
    with gdaltest.error_handler():
        geom = ogr.CreateGeometryFromWkt(geom_wkt)
    if geom is not None:
        gdaltest.post_reason('fail')
        print(geom)
        return 'fail'

    geom_wkt = 'TRIANGLE ((0 0,0 1,1 1,0 0),(0 0,0 1,1 1,0 0))'
    with gdaltest.error_handler():
        geom = ogr.CreateGeometryFromWkt(geom_wkt)
    if geom is not None:
        gdaltest.post_reason('fail')
        print(geom)
        return 'fail'

    return 'success'

###############################################################################
# Test OGRTriangle. Tests if the GEOS/SFCGAL methods are working


def ogr_geom_triangle_sfcgal():

    if not ogrtest.have_sfcgal():
        return 'skip'

    g1 = ogr.CreateGeometryFromWkt('TRIANGLE ((0 0,100 0 100,0 100 100,0 0))')
    g2 = ogr.CreateGeometryFromWkt('TRIANGLE ((-1 -1,100 0 100,0 100 100,-1 -1))')
    if not g2.Intersects(g1):
        gdaltest.post_reason('fail')
        return 'fail'

    g1 = ogr.CreateGeometryFromWkt('TRIANGLE ((0 0,1 0,0 1,0 0))')
    g2 = ogr.CreateGeometryFromWkt('TRIANGLE ((0 0,1 0,1 1,0 0))')
    g3 = g1.Intersection(g2)
    g4 = ogr.CreateGeometryFromWkt('TRIANGLE ((0.5 0.5 0,0 0 0,1 0 0,0.5 0.5 0))')
    if not g4.Equals(g3):
        gdaltest.post_reason('fail')
        return 'fail'

    return 'success'

###############################################################################
# Test OGRCircularString


def ogr_geom_circularstring():

    in_wkt = 'CIRCULARSTRING (0 0,1 1,1 -1)'

    # Test export/import Wkt
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if g1.GetGeometryType() != ogr.wkbCircularString:
        gdaltest.post_reason('fail')
        return 'fail'
    out_wkt = g1.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    if ogrtest.have_geos():
        if not g1.IsValid():
            gdaltest.post_reason('fail')
            return 'fail'

    # Test GetEnvelope()
    env = g1.GetEnvelope()
    expected_env = (0.0, 2.0, -1.0, 1.0)
    for i in range(4):
        if abs(env[i] - expected_env[i]) > 1e-8:
            gdaltest.post_reason('fail')
            print(env)
            return 'fail'

    # Test Length()
    length = g1.Length()
    expected_length = 1.5 * math.pi
    if abs(length - expected_length) > 1e-8:
        gdaltest.post_reason('fail')
        print(length)
        return 'fail'

    # Test Value()
    p = g1.Value(-1)
    expected_p = ogr.CreateGeometryFromWkt('POINT (0 0)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    p = g1.Value(0)
    expected_p = ogr.CreateGeometryFromWkt('POINT (0 0)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    p = g1.Value(length / 6.0)
    expected_p = ogr.CreateGeometryFromWkt('POINT (0.292893218813453 0.707106781186548)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)

    p = g1.Value(length / 3.0)
    expected_p = ogr.CreateGeometryFromWkt('POINT (1 1)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    p = g1.Value(length / 2.0)
    expected_p = ogr.CreateGeometryFromWkt('POINT (1.707106781186547 0.707106781186547)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    p = g1.Value(2 * length / 3.0)
    expected_p = ogr.CreateGeometryFromWkt('POINT (2 0)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    p = g1.Value(length)
    expected_p = ogr.CreateGeometryFromWkt('POINT (1 -1)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    p = g1.Value(length + 1)
    expected_p = ogr.CreateGeometryFromWkt('POINT (1 -1)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    # Test export/import Wkb
    g2 = ogr.CreateGeometryFromWkb(g1.ExportToWkb())
    out_wkt = g2.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    # With Z
    in_wkt = 'CIRCULARSTRING Z (0 0 10,1 1 20,2 0 30)'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if g1.GetGeometryType() != ogr.wkbCircularStringZ:
        gdaltest.post_reason('fail')
        return 'fail'
    out_wkt = g1.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    wkb = g1.ExportToWkb()
    isowkb = g1.ExportToIsoWkb()
    if wkb != isowkb:
        gdaltest.post_reason('fail')
        return 'fail'
    g2 = ogr.CreateGeometryFromWkb(wkb)
    out_wkt = g2.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    # Test stroking
    gdal.SetConfigOption('OGR_STROKE_CURVE', 'TRUE')
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    in_wkt = 'CIRCULARSTRING (0 0,1 1,1 -1)'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    gdal.SetConfigOption('OGR_STROKE_CURVE', 'FALSE')
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)

    expected_g = ogr.CreateGeometryFromWkt('LINESTRING (0 0,0.218168517531969 0.623489801858729,0.777479066043687 0.974927912181831,1.433883739117561 0.900968867902435,1.900968867902463 0.433883739117562,1.974927912181821 -0.222520933956316,1.623489801858719 -0.78183148246804,1 -1)')
    if ogrtest.check_feature_geometry(g1, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g1)
        return 'fail'

    in_wkt = 'CIRCULARSTRING (0 0,1 1,1 -1)'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    in_wkb = g1.ExportToWkb()

    gdal.SetConfigOption('OGR_STROKE_CURVE', 'TRUE')
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    g2 = ogr.CreateGeometryFromWkb(in_wkb)
    gdal.SetConfigOption('OGR_STROKE_CURVE', 'FALSE')
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)

    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test HasCurveGeometry
    if not g1.HasCurveGeometry():
        gdaltest.post_reason('fail')
        return 'fail'
    if not g1.HasCurveGeometry(True):
        gdaltest.post_reason('fail')
        return 'fail'

    # Test GetLinearGeometry
    g2 = g1.GetLinearGeometry(45)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test ForceToLineString
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    g2 = ogr.ForceToLineString(g1)
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test ForceToMultiLineString
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    expected_g2 = ogr.CreateGeometryFromWkt('MULTILINESTRING ((0 0,0.218168517531969 0.623489801858729,0.777479066043687 0.974927912181831,1.433883739117561 0.900968867902435,1.900968867902463 0.433883739117562,1.974927912181821 -0.222520933956316,1.623489801858719 -0.78183148246804,1 -1))')
    g2 = ogr.ForceToMultiLineString(g1)
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)
    if ogrtest.check_feature_geometry(g2, expected_g2) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test GEOS operations
    if ogrtest.have_geos():
        g2 = g1.Intersection(g1)
        if g2 is None:
            gdaltest.post_reason('fail')
            return 'fail'

    # Test CIRCULARSTRING wrapped in a GEOMETRYCOLLECTION
    in_wkt = 'GEOMETRYCOLLECTION(CIRCULARSTRING (0 0,1 1,1 -1))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)

    # Test GEOS operations
    if ogrtest.have_geos():
        g2 = g1.Intersection(g1)
        if g2 is None:
            gdaltest.post_reason('fail')
            return 'fail'

    # Test ForceToLineString
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    g2 = ogr.ForceToLineString(g1)
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test ForceToMultiLineString
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    g2 = ogr.ForceToMultiLineString(g1)
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)
    if ogrtest.check_feature_geometry(g2, expected_g2) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test stroking of full circle with 3 points. ISO draft
    # mentions that this should define a full circle, but there's an
    # ambiguity on the winding order. We choose counter-clock-wise order like
    # PostGIS. On the contrary, Microsoft for example forbids
    # such a possibility : http://msdn.microsoft.com/en-us/library/ff929141.aspx
    in_wkt = 'CIRCULARSTRING (0 0,1 0,0 0)'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    expected_g = ogr.CreateGeometryFromWkt('LINESTRING (0 0,0.116977778440514 -0.321393804843282,0.413175911166547 -0.49240387650611,0.75 -0.433012701892224,0.969846310392967 -0.171010071662835,0.969846310392967 0.171010071662835,0.75 0.433012701892224,0.413175911166547 0.49240387650611,0.116977778440514 0.321393804843282,0 0)')
    g2 = g1.GetLinearGeometry(45)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    length = g1.Length()
    expected_length = 2 * math.pi * 0.5
    if abs(length - expected_length) > 1e-8:
        gdaltest.post_reason('fail')
        print(length)
        return 'fail'

    # Test stroking of full circle (well defined)
    in_wkt = 'CIRCULARSTRING (0 0,0.5 0.5,1.0 0.0,0.5 -0.5,0.0 0.0)'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    expected_g = ogr.CreateGeometryFromWkt('LINESTRING (0 0,0.049515566048791 0.216941869558781,0.188255099070638 0.390915741234018,0.388739533021848 0.48746395609092,0.611260466978166 0.48746395609092,0.811744900929369 0.390915741234018,0.950484433951232 0.216941869558781,1 0,0.950484433951232 -0.216941869558781,0.811744900929369 -0.390915741234018,0.611260466978166 -0.48746395609092,0.388739533021848 -0.48746395609092,0.188255099070638 -0.390915741234018,0.049515566048791 -0.216941869558781,0 0)')
    g2 = g1.GetLinearGeometry(45)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    length = g1.Length()
    expected_length = 2 * math.pi * 0.5
    if abs(length - expected_length) > 1e-8:
        gdaltest.post_reason('fail')
        print(length)
        return 'fail'

    # Check segmentize
    g1.Segmentize(0.5)
    expected_g = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,0.146446609406726 0.353553390593274,0.5 0.5,0.853553390593274 0.353553390593274,1 0,0.853553390593274 -0.353553390593274,0.5 -0.5,0.146446609406726 -0.353553390593274,0 0)')
    if ogrtest.check_feature_geometry(g1, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g1)
        return 'fail'

    # Sanity check: the length must remain the same
    length = g1.Length()
    expected_length = 2 * math.pi * 0.5
    if abs(length - expected_length) > 1e-8:
        gdaltest.post_reason('fail')
        print(length)
        return 'fail'

    # Check segmentize symmetry : do exact binary comparison
    in_wkt = 'CIRCULARSTRING (0 0,1.2 1,2 0)'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    g1.Segmentize(0.25)
    in_wkt = 'CIRCULARSTRING (2 0,1.2 1,0 0)'
    g2 = ogr.CreateGeometryFromWkt(in_wkt)
    g2.Segmentize(0.25)
    for i in range(g1.GetPointCount()):
        if g1.GetPoint(i) != g2.GetPoint(g1.GetPointCount() - 1 - i):
            gdaltest.post_reason('fail')
            print(i)
            print('%.18g' % (g1.GetPoint(i)[0] - g2.GetPoint(g1.GetPointCount() - 1 - i)[0]))
            print('%.18g' % (g1.GetPoint(i)[1] - g2.GetPoint(g1.GetPointCount() - 1 - i)[1]))
            print(g1)
            print(g2)
            return 'fail'

    # Test stroking of full circle with Z
    in_wkt = 'CIRCULARSTRING (0 0 1,1 0 2,0 0 1)'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    expected_g = ogr.CreateGeometryFromWkt('LINESTRING (0 0 1,0.116977778440514 -0.321393804843282 1,0.413175911166547 -0.49240387650611 1,0.75 -0.433012701892224 1,0.969846310392967 -0.171010071662835 1,0.969846310392967 0.171010071662835 1,0.75 0.433012701892224 1,0.413175911166547 0.49240387650611 1,0.116977778440514 0.321393804843282 1,0 0 1)')
    g2 = g1.GetLinearGeometry(45)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Check segmentize
    g1.Segmentize(0.5)
    expected_g = ogr.CreateGeometryFromWkt('CIRCULARSTRING Z (0 0 1,0.146446609406726 -0.353553390593274 1.25,0.5 -0.5 1.5,0.853553390593274 -0.353553390593274 1.75,1 0 2,0.853553390593274 0.353553390593274 1.75,0.5 0.5 1.5,0.146446609406727 0.353553390593274 1.25,0 0 1)')
    if ogrtest.check_feature_geometry(g1, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g1)
        return 'fail'

    # Same as above but reverse order
    in_wkt = 'CIRCULARSTRING (0 0,0.5 -0.5,1.0 0.0,0.5 0.5,0.0 0.0)'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    expected_g = ogr.CreateGeometryFromWkt('LINESTRING (0 0,0.049515566048791 -0.216941869558781,0.188255099070638 -0.390915741234018,0.388739533021848 -0.48746395609092,0.611260466978166 -0.48746395609092,0.811744900929369 -0.390915741234018,0.950484433951232 -0.216941869558781,1 0,0.950484433951232 0.216941869558781,0.811744900929369 0.390915741234018,0.611260466978166 0.48746395609092,0.388739533021848 0.48746395609092,0.188255099070638 0.390915741234018,0.049515566048791 0.216941869558781,0 0)')
    g2 = g1.GetLinearGeometry(45)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    length = g1.Length()
    expected_length = 2 * math.pi * 0.5
    if abs(length - expected_length) > 1e-8:
        gdaltest.post_reason('fail')
        print(length)
        return 'fail'

    # Test stroking of a circular string with 3 colinear points
    in_wkt = 'CIRCULARSTRING (0 0,1 1,2 2)'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    expected_g = ogr.CreateGeometryFromWkt('LINESTRING (0 0,1 1,2 2)')
    g2 = g1.GetLinearGeometry(45)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    length = g1.Length()
    expected_length = 2 * math.sqrt(2)
    if abs(length - expected_length) > 1e-8:
        gdaltest.post_reason('fail')
        print(length)
        return 'fail'

    # Test Value()
    p = g1.Value(length / 4.0)
    expected_p = ogr.CreateGeometryFromWkt('POINT (0.5 0.5)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'
    p = g1.Value(3.0 * length / 4.0)
    expected_p = ogr.CreateGeometryFromWkt('POINT (1.5 1.5)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    # Check segmentize
    g1.Segmentize(0.5)
    expected_g = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,0.166666666666667 0.166666666666667,0.333333333333333 0.333333333333333,0.5 0.5,0.666666666666667 0.666666666666667,0.833333333333333 0.833333333333333,1 1,1.166666666666667 1.166666666666667,1.333333333333333 1.333333333333333,1.5 1.5,1.666666666666667 1.666666666666667,1.833333333333333 1.833333333333333,2 2)')
    if ogrtest.check_feature_geometry(g1, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g1)
        return 'fail'

    # Sanity check: the length must remain the same
    length = g1.Length()
    expected_length = 2 * math.sqrt(2)
    if abs(length - expected_length) > 1e-8:
        gdaltest.post_reason('fail')
        print(length)
        return 'fail'

    # Same with Z
    in_wkt = 'CIRCULARSTRING (0 0 1,1 1 2,2 2 1)'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    expected_g = ogr.CreateGeometryFromWkt('LINESTRING (0 0 1,1 1 2,2 2 1)')
    g2 = g1.GetLinearGeometry(45)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Check segmentize
    g1.Segmentize(0.5)
    expected_g = ogr.CreateGeometryFromWkt('CIRCULARSTRING Z (0 0 1,0.166666666666667 0.166666666666667 1.166666666666667,0.333333333333333 0.333333333333333 1.333333333333333,0.5 0.5 1.5,0.666666666666667 0.666666666666667 1.666666666666667,0.833333333333333 0.833333333333333 1.833333333333333,1 1 2,1.166666666666667 1.166666666666667 1.833333333333333,1.333333333333333 1.333333333333333 1.666666666666667,1.5 1.5 1.5,1.666666666666667 1.666666666666667 1.333333333333333,1.833333333333333 1.833333333333333 1.166666666666667,2 2 1)')
    if ogrtest.check_feature_geometry(g1, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g1)
        return 'fail'

    # Test Value()
    p = g1.Value(length / 4.0)
    expected_p = ogr.CreateGeometryFromWkt('POINT (0.5 0.5 1.5)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'
    p = g1.Value(3.0 * length / 4.0)
    expected_p = ogr.CreateGeometryFromWkt('POINT (1.5 1.5 1.5)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'
    in_wkt = 'CIRCULARSTRING (0 0,1 1,1 -1)'

    # Test GetEnvelope() in various cases
    cx = 1
    cy = 2
    r = 3

    # In quadrant 0
    a0 = math.pi / 3
    a1 = math.pi / 4
    a2 = math.pi / 6
    in_wkt = 'CIRCULARSTRING(%.16g %.16g,%.16g %.16g,%.16g %.16g)' % (
        cx + r * math.cos(a0), cy + r * math.sin(a0),
        cx + r * math.cos(a1), cy + r * math.sin(a1),
        cx + r * math.cos(a2), cy + r * math.sin(a2))
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    env = g1.GetEnvelope()
    expected_env = (cx + r * math.cos(a0), cx + r * math.cos(a2), cy + r * math.sin(a2), cy + r * math.sin(a0))
    for i in range(4):
        if abs(env[i] - expected_env[i]) > 1e-8:
            gdaltest.post_reason('fail')
            print(env)
            return 'fail'

    # From quadrant 0 to quadrant -1
    a0 = math.pi / 3
    a1 = math.pi / 6
    a2 = -math.pi / 6
    in_wkt = 'CIRCULARSTRING(%.16g %.16g,%.16g %.16g,%.16g %.16g)' % (
        cx + r * math.cos(a0), cy + r * math.sin(a0),
        cx + r * math.cos(a1), cy + r * math.sin(a1),
        cx + r * math.cos(a2), cy + r * math.sin(a2))
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    env = g1.GetEnvelope()
    expected_env = (cx + r * math.cos(a0), cx + r, cy + r * math.sin(a2), cy + r * math.sin(a0))
    for i in range(4):
        if abs(env[i] - expected_env[i]) > 1e-8:
            gdaltest.post_reason('fail')
            print(env)
            return 'fail'

    # From quadrant 0 to quadrant 3
    a0 = math.pi / 3
    a1 = math.pi - math.pi / 3
    a2 = -math.pi / 6
    in_wkt = 'CIRCULARSTRING(%.16g %.16g,%.16g %.16g,%.16g %.16g)' % (
        cx + r * math.cos(a0), cy + r * math.sin(a0),
        cx + r * math.cos(a1), cy + r * math.sin(a1),
        cx + r * math.cos(a2), cy + r * math.sin(a2))
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    env = g1.GetEnvelope()
    expected_env = (cx - r, cx + r * math.cos(a2), cy - r, cy + r)
    for i in range(4):
        if abs(env[i] - expected_env[i]) > 1e-8:
            gdaltest.post_reason('fail')
            print(env)
            return 'fail'

    # From quadrant 0 to quadrant 4
    a0 = math.pi / 3
    a1 = math.pi - math.pi / 3
    a2 = math.pi / 6
    in_wkt = 'CIRCULARSTRING(%.16g %.16g,%.16g %.16g,%.16g %.16g)' % (
        cx + r * math.cos(a0), cy + r * math.sin(a0),
        cx + r * math.cos(a1), cy + r * math.sin(a1),
        cx + r * math.cos(a2), cy + r * math.sin(a2))
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    env = g1.GetEnvelope()
    expected_env = (cx - r, cx + r, cy - r, cy + r)
    for i in range(4):
        if abs(env[i] - expected_env[i]) > 1e-8:
            gdaltest.post_reason('fail')
            print(env)
            return 'fail'

    # Full circle
    a0 = math.pi / 3
    a1 = math.pi + math.pi / 3
    a2 = math.pi / 3
    in_wkt = 'CIRCULARSTRING(%.16g %.16g,%.16g %.16g,%.16g %.16g)' % (
        cx + r * math.cos(a0), cy + r * math.sin(a0),
        cx + r * math.cos(a1), cy + r * math.sin(a1),
        cx + r * math.cos(a2), cy + r * math.sin(a2))
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    env = g1.GetEnvelope()
    expected_env = (cx - r, cx + r, cy - r, cy + r)
    for i in range(4):
        if abs(env[i] - expected_env[i]) > 1e-8:
            gdaltest.post_reason('fail')
            print(env)
            return 'fail'

    # Error case : not enough points
    in_wkt = 'CIRCULARSTRING (0 0)'
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    g = ogr.CreateGeometryFromWkt(in_wkt)
    gdal.PopErrorHandler()
    if g is not None:
        gdaltest.post_reason('fail')
        return 'fail'

    # EMPTY
    for in_wkt in ['CIRCULARSTRING EMPTY', 'CIRCULARSTRING Z EMPTY']:
        g1 = ogr.CreateGeometryFromWkt(in_wkt)
        out_wkt = g1.ExportToWkt()
        if in_wkt != out_wkt:
            gdaltest.post_reason('fail')
            print(in_wkt)
            print(out_wkt)
            return 'fail'
        if g1.Length() != 0.0:
            gdaltest.post_reason('fail')
            print(in_wkt)
            return 'fail'

        g2 = ogr.CreateGeometryFromWkb(g1.ExportToWkb())
        out_wkt = g2.ExportToWkt()
        if in_wkt != out_wkt:
            gdaltest.post_reason('fail')
            print(in_wkt)
            print(out_wkt)
            return 'fail'

    return 'success'

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


def ogr_geom_compoundcurve():

    in_wkt = 'COMPOUNDCURVE (CIRCULARSTRING (0 0,1 1,1 -1))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if g1.GetGeometryType() != ogr.wkbCompoundCurve:
        gdaltest.post_reason('fail')
        return 'fail'
    out_wkt = g1.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    if g1.GetGeometryCount() != 1:
        gdaltest.post_reason('fail')
        return 'fail'
    if g1.GetGeometryRef(0).ExportToWkt() != 'CIRCULARSTRING (0 0,1 1,1 -1)':
        gdaltest.post_reason('fail')
        return 'fail'

    env = g1.GetEnvelope()
    expected_env = (0.0, 2.0, -1.0, 1.0)
    for i in range(4):
        if abs(env[i] - expected_env[i]) > 1e-8:
            gdaltest.post_reason('fail')
            print(env)
            return 'fail'

    length = g1.Length()
    expected_length = 1.5 * math.pi
    if abs(length - expected_length) > 1e-8:
        gdaltest.post_reason('fail')
        print(length)
        return 'fail'

    g2 = ogr.CreateGeometryFromWkb(g1.ExportToWkb())
    out_wkt = g2.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if not g1.HasCurveGeometry():
        gdaltest.post_reason('fail')
        return 'fail'
    if not g1.HasCurveGeometry(True):
        gdaltest.post_reason('fail')
        return 'fail'

    # CreateGeometryFromWkt of LINESTRING
    in_wkt = 'COMPOUNDCURVE ((0 0,0 10))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if not g1.HasCurveGeometry():
        gdaltest.post_reason('fail')
        return 'fail'
    if g1.HasCurveGeometry(True):
        gdaltest.post_reason('fail')
        return 'fail'

    # With Z
    in_wkt = 'COMPOUNDCURVE Z (CIRCULARSTRING Z (0 0 10,1 1 20,2 0 30),(2 0 30,0 0 10))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if g1.GetGeometryType() != ogr.wkbCompoundCurveZ:
        gdaltest.post_reason('fail')
        return 'fail'
    out_wkt = g1.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    env = g1.GetEnvelope()
    expected_env = (0.0, 2.0, 0.0, 1.0)
    for i in range(4):
        if abs(env[i] - expected_env[i]) > 1e-8:
            gdaltest.post_reason('fail')
            print(env)
            return 'fail'

    env = g1.GetEnvelope3D()
    expected_env = (0.0, 2.0, 0.0, 1.0, 10, 30)
    for i in range(6):
        if abs(env[i] - expected_env[i]) > 1e-8:
            gdaltest.post_reason('fail')
            print(env)
            return 'fail'

    # Test Value()
    p = g1.Value(-1e-3)
    expected_p = ogr.CreateGeometryFromWkt('POINT (0 0 10)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    p = g1.Value(math.pi / 2.0)
    expected_p = ogr.CreateGeometryFromWkt('POINT (1 1 20)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    p = g1.Value(math.pi)
    expected_p = ogr.CreateGeometryFromWkt('POINT (2 0 30)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    p = g1.Value(math.pi + 1)
    expected_p = ogr.CreateGeometryFromWkt('POINT (1 0 20)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    p = g1.Value(math.pi + 2 + 1e-3)
    expected_p = ogr.CreateGeometryFromWkt('POINT (0 0 10)')
    if ogrtest.check_feature_geometry(p, expected_p) != 0:
        gdaltest.post_reason('fail')
        print(p)
        return 'fail'

    wkb = g1.ExportToWkb()
    isowkb = g1.ExportToIsoWkb()
    if wkb != isowkb:
        gdaltest.post_reason('fail')
        return 'fail'
    g2 = ogr.CreateGeometryFromWkb(wkb)
    out_wkt = g2.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    # Several parts
    in_wkt = 'COMPOUNDCURVE (CIRCULARSTRING (0 0,1 1,1 -1),(1 -1,0 0))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if g1.GetGeometryType() != ogr.wkbCompoundCurve:
        gdaltest.post_reason('fail')
        return 'fail'
    out_wkt = g1.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    if not g1.Equals(g1):
        gdaltest.post_reason('fail')
        return 'fail'

    if not g1.Equals(g1.Clone()):
        gdaltest.post_reason('fail')
        return 'fail'

    if g1.Equals(ogr.CreateGeometryFromWkt('POINT(0 0)')):
        gdaltest.post_reason('fail')
        return 'fail'

    if g1.Equals(ogr.CreateGeometryFromWkt('COMPOUNDCURVE (CIRCULARSTRING (0 0,1 1,1 -1))')):
        gdaltest.post_reason('fail')
        return 'fail'

    if g1.Equals(ogr.CreateGeometryFromWkt('COMPOUNDCURVE (CIRCULARSTRING (0 0,1 1,1 -1),(1 -1,0 1))')):
        gdaltest.post_reason('fail')
        return 'fail'

    length = g1.Length()
    expected_length = 1.5 * math.pi + math.sqrt(2)
    if abs(length - expected_length) > 1e-8:
        gdaltest.post_reason('fail')
        print(length)
        return 'fail'

    g2 = ogr.CreateGeometryFromWkb(g1.ExportToWkb())
    out_wkt = g2.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    # Test stroking
    gdal.SetConfigOption('OGR_STROKE_CURVE', 'TRUE')
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    in_wkt = 'COMPOUNDCURVE (CIRCULARSTRING (0 0,1 1,1 -1))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    gdal.SetConfigOption('OGR_STROKE_CURVE', 'FALSE')
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)

    expected_g = ogr.CreateGeometryFromWkt('LINESTRING (0 0,0.218168517531969 0.623489801858729,0.777479066043687 0.974927912181831,1.433883739117561 0.900968867902435,1.900968867902463 0.433883739117562,1.974927912181821 -0.222520933956316,1.623489801858719 -0.78183148246804,1 -1)')
    if ogrtest.check_feature_geometry(g1, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g1)
        return 'fail'

    in_wkt = 'COMPOUNDCURVE (CIRCULARSTRING (0 0,1 1,1 -1))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    in_wkb = g1.ExportToWkb()

    gdal.SetConfigOption('OGR_STROKE_CURVE', 'TRUE')
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    g2 = ogr.CreateGeometryFromWkb(in_wkb)
    gdal.SetConfigOption('OGR_STROKE_CURVE', 'FALSE')
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)

    expected_g = ogr.CreateGeometryFromWkt('LINESTRING (0 0,0.218168517531969 0.623489801858729,0.777479066043687 0.974927912181831,1.433883739117561 0.900968867902435,1.900968867902463 0.433883739117562,1.974927912181821 -0.222520933956316,1.623489801858719 -0.78183148246804,1 -1)')
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    g2 = g1.GetLinearGeometry(45)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    if not g1.HasCurveGeometry():
        gdaltest.post_reason('fail')
        return 'fail'

    if not g1.HasCurveGeometry(True):
        gdaltest.post_reason('fail')
        return 'fail'

    g2 = g1.GetLinearGeometry(45)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    g2 = ogr.ForceToLineString(g1)
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    expected_g = ogr.CreateGeometryFromWkt('MULTILINESTRING ((0 0,0.218168517531969 0.623489801858729,0.777479066043687 0.974927912181831,1.433883739117561 0.900968867902435,1.900968867902463 0.433883739117562,1.974927912181821 -0.222520933956316,1.623489801858719 -0.78183148246804,1 -1))')
    g2 = ogr.ForceToMultiLineString(g1)
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Check segmentize
    g1.Segmentize(0.5)
    expected_g = ogr.CreateGeometryFromWkt('COMPOUNDCURVE (CIRCULARSTRING (0 0,0.076120467488713 0.38268343236509,0.292893218813453 0.707106781186548,0.61731656763491 0.923879532511287,1 1,1.38268343236509 0.923879532511287,1.707106781186547 0.707106781186547,1.923879532511287 0.38268343236509,2 0,1.923879532511287 -0.38268343236509,1.707106781186547 -0.707106781186547,1.38268343236509 -0.923879532511287,1 -1))')
    if ogrtest.check_feature_geometry(g1, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g1)
        return 'fail'

    # Error case : not enough points
    in_wkt = 'COMPOUNDCURVE ((0 0))'
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    g = ogr.CreateGeometryFromWkt(in_wkt)
    gdal.PopErrorHandler()
    if g is not None:
        gdaltest.post_reason('fail')
        return 'fail'

    # Error case : invalid curve
    in_wkt = 'COMPOUNDCURVE (COMPOUNDCURVE EMPTY)'
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    g = ogr.CreateGeometryFromWkt(in_wkt)
    gdal.PopErrorHandler()
    if g is not None:
        gdaltest.post_reason('fail')
        return 'fail'

    # Error case : non contiguous curves
    in_wkt = 'COMPOUNDCURVE ((0 0,1 1),(2 2,3 3))'
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    g = ogr.CreateGeometryFromWkt(in_wkt)
    gdal.PopErrorHandler()
    if g is not None:
        gdaltest.post_reason('fail')
        return 'fail'

    # Error case : non contiguous curves
    in_wkt = 'COMPOUNDCURVE (EMPTY,(2 2,3 3))'
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    g = ogr.CreateGeometryFromWkt(in_wkt)
    gdal.PopErrorHandler()
    if g is not None:
        gdaltest.post_reason('fail')
        return 'fail'

    # Error case : non contiguous curves
    in_wkt = 'COMPOUNDCURVE ((2 2,3 3), EMPTY)'
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    g = ogr.CreateGeometryFromWkt(in_wkt)
    gdal.PopErrorHandler()
    if g is not None:
        gdaltest.post_reason('fail')
        return 'fail'

    g = ogr.Geometry(ogr.wkbCompoundCurve)
    g.AddGeometry(ogr.CreateGeometryFromWkt('LINESTRING(0 0,1 1)'))
    if g.ExportToWkt() != 'COMPOUNDCURVE ((0 0,1 1))':
        gdaltest.post_reason('fail')
        return 'fail'

    gdal.PushErrorHandler('CPLQuietErrorHandler')
    g.AddGeometry(ogr.CreateGeometryFromWkt('LINESTRING(0 0,1 1)'))
    gdal.PopErrorHandler()
    if g.ExportToWkt() != 'COMPOUNDCURVE ((0 0,1 1),(1 1,0 0))':
        gdaltest.post_reason('fail')
        return 'fail'

    g = ogr.Geometry(ogr.wkbCompoundCurve)
    g.AddGeometryDirectly(ogr.CreateGeometryFromWkt('LINESTRING(0 0,1 1)'))
    if g.ExportToWkt() != 'COMPOUNDCURVE ((0 0,1 1))':
        gdaltest.post_reason('fail')
        return 'fail'

    gdal.PushErrorHandler('CPLQuietErrorHandler')
    g.AddGeometryDirectly(ogr.CreateGeometryFromWkt('LINESTRING(0 0,1 1)'))
    gdal.PopErrorHandler()
    if g.ExportToWkt() != 'COMPOUNDCURVE ((0 0,1 1),(1 1,0 0))':
        gdaltest.post_reason('fail')
        return 'fail'

    # Cannot add compoundcurve in compoundcurve
    g = ogr.Geometry(ogr.wkbCompoundCurve)
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    g.AddGeometryDirectly(ogr.CreateGeometryFromWkt('COMPOUNDCURVE((1 1,2 2))'))
    gdal.PopErrorHandler()
    if g.ExportToWkt() != 'COMPOUNDCURVE EMPTY':
        gdaltest.post_reason('fail')
        return 'fail'

    # Check that discretization is not sensitive to winding order
    g1 = ogr.CreateGeometryFromWkt('COMPOUNDCURVE((-1 0,0 1),CIRCULARSTRING (0 1,0.25 0,0.1 -0.5),(0.1 -0.5,-1 0))')
    g2 = g1.GetLinearGeometry(1.5)
    g1 = ogr.CreateGeometryFromWkt('COMPOUNDCURVE((-1 0,0.1 -0.5),CIRCULARSTRING (0.1 -0.5,0.25 0,0 1),(0 1,-1 0))')
    g3 = g1.GetLinearGeometry(1.5)
    p_count = g2.GetPointCount()
    for i in range(p_count):
        # yes we do strict (binary) comparison. This is really intended.
        # The curves must be exactly the same, despite our stealth mode
        if g2.GetX(i) != g3.GetX(p_count - 1 - i) or \
           g2.GetY(i) != g3.GetY(p_count - 1 - i):
            gdaltest.post_reason('fail')
            print(g2)
            print(g3)
            print(i)
            print(abs(g2.GetX(i) - g3.GetX(p_count - 1 - i)))
            print(abs(g2.GetY(i) - g3.GetY(p_count - 1 - i)))
            return 'fail'

    # Test Transform
    sr = osr.SpatialReference()
    sr.ImportFromEPSG(4326)
    g.AssignSpatialReference(sr)
    g.TransformTo(sr)

    # Invalid wkb
    wkb_list = ['\x01\x09\x00\x00\x00\x01\x00\x00\x00',  # subgeometry declared but not present
                '\x01\x09\x00\x00\x00\xff\xff\xff\x7f',  # 2 billion subgeometries declared !
                '\x01\x09\x00\x00\x00\x01\x00\x00\x00\x01\xff\x00\x00\x00\x00\x00\x00\x00',  # subgeometry invalid: unknown type
                '\x01\x09\x00\x00\x00\x01\x00\x00\x00\x01\x02\x00\x00\x00\x01\x00\x00\x00',  # subgeometry invalid: linestring truncated
                '\x01\x09\x00\x00\x00\x01\x00\x00\x00\x01\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',  # subgeometry invalid: linestring with one point
                '\x01\x09\x00\x00\x00\x01\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',  # subgeometry invalid: point
                '\x01\x09\x00\x00\x00\x01\x00\x00\x00\x01\x09\x00\x00\x00\x00\x00\x00\x00',  # subgeometry invalid: compoundcurve
                ]
    for wkb in wkb_list:
        gdal.PushErrorHandler('CPLQuietErrorHandler')
        g = ogr.CreateGeometryFromWkb(wkb)
        gdal.PopErrorHandler()
        if g is not None:
            gdaltest.post_reason('fail')
            print(wkb)
            return 'fail'

    # EMPTY
    for in_wkt in ['COMPOUNDCURVE EMPTY', 'COMPOUNDCURVE Z EMPTY']:
        g1 = ogr.CreateGeometryFromWkt(in_wkt)
        out_wkt = g1.ExportToWkt()
        if in_wkt != out_wkt:
            gdaltest.post_reason('fail')
            print(in_wkt)
            print(out_wkt)
            return 'fail'
        if g1.Length() != 0.0:
            gdaltest.post_reason('fail')
            print(in_wkt)
            return 'fail'

        g2 = ogr.CreateGeometryFromWkb(g1.ExportToWkb())
        out_wkt = g2.ExportToWkt()
        if in_wkt != out_wkt:
            gdaltest.post_reason('fail')
            print(in_wkt)
            print(out_wkt)
            return 'fail'

    return 'success'

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


def ogr_geom_curvepolygon():

    in_wkt = 'CURVEPOLYGON (CIRCULARSTRING (0 0,1 0,0 0))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if g1.GetGeometryType() != ogr.wkbCurvePolygon:
        gdaltest.post_reason('fail')
        return 'fail'
    out_wkt = g1.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    if ogrtest.have_geos():
        p1 = g1.PointOnSurface()
        if (p1.GetX() - 0.5) * (p1.GetX() - 0.5) + p1.GetY() * p1.GetY() > 0.5 * 0.5:
            gdaltest.post_reason('fail')
            print(p1)
            return 'fail'

    env = g1.GetEnvelope()
    expected_env = (0.0, 1.0, -0.5, 0.5)
    for i in range(4):
        if abs(env[i] - expected_env[i]) > 1e-8:
            gdaltest.post_reason('fail')
            print(env)
            return 'fail'

    area = g1.Area()
    expected_area = math.pi * 0.5 * 0.5
    if abs(area - expected_area) > 1e-8:
        gdaltest.post_reason('fail')
        print(area)
        print(expected_area)
        return 'fail'

    g2 = ogr.CreateGeometryFromWkb(g1.ExportToWkb())
    out_wkt = g2.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    # CURVEPOLYGON of LINESTRING
    in_wkt = 'CURVEPOLYGON ((0 0,0 10,10 10,10 0,0 0))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if not g1.HasCurveGeometry():
        gdaltest.post_reason('fail')
        return 'fail'
    if g1.HasCurveGeometry(True):
        gdaltest.post_reason('fail')
        return 'fail'

    # With Z
    in_wkt = 'CURVEPOLYGON Z (CIRCULARSTRING Z (0 0 10,1 0 10,0 0 10))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if g1.GetGeometryType() != ogr.wkbCurvePolygonZ:
        gdaltest.post_reason('fail')
        return 'fail'
    out_wkt = g1.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    wkb = g1.ExportToWkb()
    isowkb = g1.ExportToIsoWkb()
    if wkb != isowkb:
        gdaltest.post_reason('fail')
        return 'fail'
    g2 = ogr.CreateGeometryFromWkb(wkb)
    out_wkt = g2.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    # Test stroking
    gdal.SetConfigOption('OGR_STROKE_CURVE', 'TRUE')
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    in_wkt = 'CURVEPOLYGON (CIRCULARSTRING (0 0,1 0,0 0))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    gdal.SetConfigOption('OGR_STROKE_CURVE', 'FALSE')
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)

    expected_g = ogr.CreateGeometryFromWkt('POLYGON ((0 0,0.116977778440514 -0.321393804843282,0.413175911166547 -0.49240387650611,0.75 -0.433012701892224,0.969846310392967 -0.171010071662835,0.969846310392967 0.171010071662835,0.75 0.433012701892224,0.413175911166547 0.49240387650611,0.116977778440514 0.321393804843282,0 0))')
    if ogrtest.check_feature_geometry(g1, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g1)
        return 'fail'

    in_wkt = 'CURVEPOLYGON (CIRCULARSTRING (0 0,1 0,0 0))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    in_wkb = g1.ExportToWkb()

    gdal.SetConfigOption('OGR_STROKE_CURVE', 'TRUE')
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    g2 = ogr.CreateGeometryFromWkb(in_wkb)
    gdal.SetConfigOption('OGR_STROKE_CURVE', 'FALSE')
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)

    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test HasCurveGeometry
    if not g1.HasCurveGeometry():
        gdaltest.post_reason('fail')
        return 'fail'
    if not g1.HasCurveGeometry(True):
        gdaltest.post_reason('fail')
        return 'fail'

    # Test GetLinearGeometry
    g2 = g1.GetLinearGeometry(45)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test ForceToPolygon
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    g2 = ogr.ForceToPolygon(g1)
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test ForceToMultiPolygon
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    expected_g2 = ogr.CreateGeometryFromWkt('MULTIPOLYGON (((0 0,0.116977778440514 -0.321393804843282,0.413175911166547 -0.49240387650611,0.75 -0.433012701892224,0.969846310392967 -0.171010071662835,0.969846310392967 0.171010071662835,0.75 0.433012701892224,0.413175911166547 0.49240387650611,0.116977778440514 0.321393804843282,0 0)))')
    g2 = ogr.ForceToMultiPolygon(g1)
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)
    if ogrtest.check_feature_geometry(g2, expected_g2) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test ForceToMultiLineString
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    g2 = ogr.ForceToMultiLineString(g1)
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)
    expected_g3 = ogr.CreateGeometryFromWkt('MULTILINESTRING ((0 0,0.116977778440514 -0.321393804843282,0.413175911166547 -0.49240387650611,0.75 -0.433012701892224,0.969846310392967 -0.171010071662835,0.969846310392967 0.171010071662835,0.75 0.433012701892224,0.413175911166547 0.49240387650611,0.116977778440514 0.321393804843282,0 0))')
    if ogrtest.check_feature_geometry(g2, expected_g3) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test GEOS operations
    if ogrtest.have_geos():
        g2 = g1.Intersection(g1)
        if g2 is None:
            gdaltest.post_reason('fail')
            return 'fail'

    # Test CURVEPOLYGON and COMPOUNDCURVE, CIRCULARSTRING, LINESTRING
    in_wkt = 'CURVEPOLYGON (COMPOUNDCURVE (CIRCULARSTRING (0 0,1 1,2 0),(2 0,0 0)),(0.1 0.1,0.1 0.2,0.2 0.2,0.2 0.1,0.1 0.1),CIRCULARSTRING (0.25 0.25,0.75 0.25,0.25 0.25))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    g2 = ogr.CreateGeometryFromWkb(g1.ExportToWkb())
    if g2.ExportToWkt() != in_wkt:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test CURVEPOLYGON wrapped in a GEOMETRYCOLLECTION
    in_wkt = 'GEOMETRYCOLLECTION(CURVEPOLYGON(CIRCULARSTRING (0 0,1 0,0 0)))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    g2 = ogr.CreateGeometryFromWkb(g1.ExportToWkb())
    if not g1.Equals(g2):
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test GEOS operations
    if ogrtest.have_geos():
        g2 = g1.Intersection(g1)
        if g2 is None:
            gdaltest.post_reason('fail')
            return 'fail'

    # Test ForceToPolygon
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    g2 = ogr.ForceToPolygon(g1)
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test ForceToMultiPolygon
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    g2 = ogr.ForceToMultiPolygon(g1)
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)
    if ogrtest.check_feature_geometry(g2, expected_g2) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Error case : not enough points
    in_wkt = 'CURVEPOLYGON ((0 0,0 1,0 0))'
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    g = ogr.CreateGeometryFromWkt(in_wkt)
    gdal.PopErrorHandler()
    if g is not None:
        gdaltest.post_reason('fail')
        return 'fail'

    # Error case : wrong sub-geometry type
    in_wkt = 'CURVEPOLYGON (POINT EMPTY)'
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    g = ogr.CreateGeometryFromWkt(in_wkt)
    gdal.PopErrorHandler()
    if g is not None:
        gdaltest.post_reason('fail')
        return 'fail'

    # Error case: non closed ring
    in_wkt = 'CURVEPOLYGON ((0 0,0 1,1 1,1 0))'
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    g = ogr.CreateGeometryFromWkt(in_wkt)
    gdal.PopErrorHandler()
    if g is not None:
        gdaltest.post_reason('fail')
        return 'fail'

    # Area
    g = ogr.CreateGeometryFromWkt('CURVEPOLYGON ((0 0,1 1,1 0,0 0))')
    if g.Area() != 0.5:
        gdaltest.post_reason('fail')
        return 'fail'

    g = ogr.CreateGeometryFromWkt('CURVEPOLYGON (COMPOUNDCURVE((0 0,1 1,1 0,0 0)))')
    if g.Area() != 0.5:
        gdaltest.post_reason('fail')
        return 'fail'

    g = ogr.CreateGeometryFromWkt('CURVEPOLYGON (COMPOUNDCURVE((0 0,1 1),(1 1,1 0,0 0)))')
    if g.Area() != 0.5:
        gdaltest.post_reason('fail')
        return 'fail'

    g = ogr.CreateGeometryFromWkt('CURVEPOLYGON ((100000000 100000000,100000001 100000001,100000001 100000000,100000000 100000000))')
    if g.Area() != 0.5:
        gdaltest.post_reason('fail')
        return 'fail'

    # Equals
    g1 = ogr.CreateGeometryFromWkt('CURVEPOLYGON ((0 0,1 1,1 0,0 0),CIRCULARSTRING(0.75 0.5,0.85 0.5,0.75 0.5))')
    if not g1.Equals(g1):
        gdaltest.post_reason('fail')
        return 'fail'

    if not g1.Equals(g1.Clone()):
        gdaltest.post_reason('fail')
        return 'fail'

    if g1.Equals(ogr.CreateGeometryFromWkt('POINT(0 0)')):
        gdaltest.post_reason('fail')
        return 'fail'

    if g1.Equals(ogr.CreateGeometryFromWkt('CURVEPOLYGON ((0 0,1 1,1 0,0 0))')):
        gdaltest.post_reason('fail')
        return 'fail'

    # Intersects optimizations on a circle
    g1 = ogr.CreateGeometryFromWkt('CURVEPOLYGON (CIRCULARSTRING (0 0,2 0,0 0))')
    # Point slightly within circle
    p1 = ogr.CreateGeometryFromWkt('POINT (%.16g %.16g)' % (1 + math.cos(math.pi / 6) - 1e-4, math.sin(math.pi / 6)))
    # To prove that we don't use discretization
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    res = g1.Intersects(p1)
    res = res & p1.Intersects(g1)
    res = res & g1.Contains(p1)
    res = res & p1.Within(g1)
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)
    if not res:
        gdaltest.post_reason('fail')
        return 'fail'

    # Test point slightly outside circle
    p2 = ogr.CreateGeometryFromWkt('POINT (%.16g %.16g)' % (1 + math.cos(math.pi / 6) + 1e-4, math.sin(math.pi / 6)))
    if p2.Within(g1):
        gdaltest.post_reason('fail')
        return 'fail'

    # Full circle defined by 2 arcs
    g1 = ogr.CreateGeometryFromWkt('CURVEPOLYGON (CIRCULARSTRING (0 0,1 1,2 0,1 -1,0 0))')
    if not p1.Within(g1):
        gdaltest.post_reason('fail')
        return 'fail'

    # Same but in reverse order
    g1 = ogr.CreateGeometryFromWkt('CURVEPOLYGON (CIRCULARSTRING (0 0,1 -1,2 0,1 1,0 0))')
    if not p1.Within(g1):
        gdaltest.post_reason('fail')
        return 'fail'

    # This is not a circle
    p2 = ogr.CreateGeometryFromWkt('POINT (%.16g %.16g)' % (1 + math.cos(math.pi / 6) - 1e-2, math.sin(math.pi / 6)))
    g1 = ogr.CreateGeometryFromWkt('CURVEPOLYGON (CIRCULARSTRING (0 0,1 1,2 0,1 1,0 0))')
    if p2.Within(g1):
        gdaltest.post_reason('fail')
        return 'fail'

    # Test area on circle in 2 pieces
    g1 = ogr.CreateGeometryFromWkt('CURVEPOLYGON (CIRCULARSTRING (0 0,1 1,2 0,1 -1,0 0))')
    area = g1.Area()
    expected_area = math.pi
    if abs(area - expected_area) > 1e-10:
        gdaltest.post_reason('fail')
        print(area)
        print(expected_area)
        return 'fail'

    # Test area on hippodrome
    g1 = ogr.CreateGeometryFromWkt('CURVEPOLYGON (CIRCULARSTRING (0 0,1 1,2 0,2 -1,2 -2,1 -3,0 -2,0 -1,0 0))')
    area = g1.Area()
    expected_area = math.pi + 2 * 2
    if abs(area - expected_area) > 1e-10:
        gdaltest.post_reason('fail')
        print(area)
        print(expected_area)
        return 'fail'

    # Same hippodrome but with different WKT
    g1 = ogr.CreateGeometryFromWkt('CURVEPOLYGON (COMPOUNDCURVE(CIRCULARSTRING (0 0,1 1,2 0),(2 0,2 -2),CIRCULARSTRING(2 -2,1 -3,0 -2),(0 -2,0 0)))')
    area = g1.Area()
    expected_area = math.pi + 2 * 2
    if abs(area - expected_area) > 1e-10:
        gdaltest.post_reason('fail')
        print(area)
        print(expected_area)
        return 'fail'

    # Similar, but with concave part (does not trigger optimization)
    g1 = ogr.CreateGeometryFromWkt('CURVEPOLYGON (COMPOUNDCURVE(CIRCULARSTRING (0 0,1 1,2 0),(2 0,2 -2),CIRCULARSTRING(2 -2,1 -1,0 -2),(0 -2,0 0)))')
    area = g1.Area()
    expected_area = 2 * 2
    if abs(area - expected_area) > 1e-10:
        gdaltest.post_reason('fail')
        print(area)
        print(expected_area)
        return 'fail'

    # EMPTY
    for in_wkt in ['CURVEPOLYGON EMPTY', 'CURVEPOLYGON Z EMPTY']:
        g1 = ogr.CreateGeometryFromWkt(in_wkt)
        out_wkt = g1.ExportToWkt()
        if in_wkt != out_wkt:
            gdaltest.post_reason('fail')
            print(in_wkt)
            print(out_wkt)
            return 'fail'
        if g1.Area() != 0.0:
            gdaltest.post_reason('fail')
            print(in_wkt)
            return 'fail'

        g2 = ogr.CreateGeometryFromWkb(g1.ExportToWkb())
        out_wkt = g2.ExportToWkt()
        if in_wkt != out_wkt:
            gdaltest.post_reason('fail')
            print(in_wkt)
            print(out_wkt)
            return 'fail'

    # Empty CircularString
    g = ogr.Geometry(ogr.wkbCurvePolygon)
    g.AddGeometry(ogr.Geometry(ogr.wkbCircularString))
    if g.Area() != 0:
        gdaltest.post_reason('fail')
        print(g.Area())
        return 'fail'

    # Non-convex CircularString
    g = ogr.CreateGeometryFromWkt('CURVEPOLYGON( COMPOUNDCURVE( CIRCULARSTRING(0 0,0.5 -0.5,1 0,1.5 0.5,2 0), (2 0,2 1,0 1,0 0) ) )')
    if abs(g.Area() - 2.0) > 1e-10:
        gdaltest.post_reason('fail')
        print(g.Area())
        return 'fail'

    return 'success'

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


def ogr_geom_multicurve():

    # Simple test
    in_wkt = 'MULTICURVE (CIRCULARSTRING (0 0,1 0,0 0))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if g1.GetGeometryType() != ogr.wkbMultiCurve:
        gdaltest.post_reason('fail')
        return 'fail'
    out_wkt = g1.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    if g1.GetDimension() != 1:
        print(g1.GetDimension())
        return 'fail'

    env = g1.GetEnvelope()
    expected_env = (0.0, 1.0, -0.5, 0.5)
    for i in range(4):
        if abs(env[i] - expected_env[i]) > 1e-8:
            gdaltest.post_reason('fail')
            print(env)
            return 'fail'

    length = g1.Length()
    expected_length = 2 * math.pi * 0.5
    if abs(length - expected_length) > 1e-8:
        gdaltest.post_reason('fail')
        print(length)
        return 'fail'

    g2 = ogr.CreateGeometryFromWkb(g1.ExportToWkb())
    out_wkt = g2.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    if not g1.HasCurveGeometry():
        gdaltest.post_reason('fail')
        return 'fail'
    if not g1.HasCurveGeometry(True):
        gdaltest.post_reason('fail')
        return 'fail'

    # MULTICURVE of LINESTRING
    in_wkt = 'MULTICURVE ((0 0,1 0))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if not g1.HasCurveGeometry():
        gdaltest.post_reason('fail')
        return 'fail'
    if g1.HasCurveGeometry(True):
        gdaltest.post_reason('fail')
        return 'fail'

    # Z
    in_wkt = 'MULTICURVE Z (CIRCULARSTRING Z (0 0 10,1 0 10,0 0 10))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if g1.GetGeometryType() != ogr.wkbMultiCurveZ:
        gdaltest.post_reason('fail')
        return 'fail'
    out_wkt = g1.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    g2 = ogr.CreateGeometryFromWkb(g1.ExportToWkb())
    out_wkt = g2.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    # WKT with all possible sub geometries
    in_wkt = 'MULTICURVE (CIRCULARSTRING (0 0,1 0,0 0),(0 0,1 1),COMPOUNDCURVE ((0 0,1 1),CIRCULARSTRING (1 1,2 2,3 3)))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    out_wkt = g1.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    g2 = ogr.CreateGeometryFromWkb(g1.ExportToWkb())
    out_wkt = g2.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    # Test ForceToMultiLineString
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    g2 = ogr.ForceToMultiLineString(g1)
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)
    expected_g = 'MULTILINESTRING ((0 0,0.116977778440514 -0.321393804843282,0.413175911166547 -0.49240387650611,0.75 -0.433012701892224,0.969846310392967 -0.171010071662835,0.969846310392967 0.171010071662835,0.75 0.433012701892224,0.413175911166547 0.49240387650611,0.116977778440514 0.321393804843282,0 0),(0 0,1 1),(0 0,1 1,2 2,3 3))'
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test GetLinearGeometry
    g2 = g1.GetLinearGeometry(45)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Error case : wrong sub-geometry type
    in_wkt = 'MULTILINESTRING (POINT EMPTY)'
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    g = ogr.CreateGeometryFromWkt(in_wkt)
    gdal.PopErrorHandler()
    if g is not None:
        gdaltest.post_reason('fail')
        return 'fail'

    return 'success'

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


def ogr_geom_multisurface():

    # Simple test
    in_wkt = 'MULTISURFACE (CURVEPOLYGON (CIRCULARSTRING (0 0,1 0,0 0)))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if g1.GetGeometryType() != ogr.wkbMultiSurface:
        gdaltest.post_reason('fail')
        return 'fail'
    out_wkt = g1.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    if g1.GetDimension() != 2:
        print(g1.GetDimension())
        return 'fail'

    env = g1.GetEnvelope()
    expected_env = (0.0, 1.0, -0.5, 0.5)
    for i in range(4):
        if abs(env[i] - expected_env[i]) > 1e-8:
            gdaltest.post_reason('fail')
            print(env)
            return 'fail'

    area = g1.Area()
    expected_area = math.pi * 0.5 * 0.5
    if abs(area - expected_area) > 1e-8:
        gdaltest.post_reason('fail')
        print(area)
        return 'fail'

    g2 = ogr.CreateGeometryFromWkb(g1.ExportToWkb())
    out_wkt = g2.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    if not g1.HasCurveGeometry():
        gdaltest.post_reason('fail')
        return 'fail'
    if not g1.HasCurveGeometry(True):
        gdaltest.post_reason('fail')
        return 'fail'

    # Z
    in_wkt = 'MULTISURFACE Z (CURVEPOLYGON Z (CIRCULARSTRING Z (0 0 10,1 0 10,0 0 10)))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if g1.GetGeometryType() != ogr.wkbMultiSurfaceZ:
        gdaltest.post_reason('fail')
        return 'fail'
    out_wkt = g1.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    g2 = ogr.CreateGeometryFromWkb(g1.ExportToWkb())
    out_wkt = g2.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    # MULTISURFACE of POLYGON
    in_wkt = 'MULTISURFACE (((0 0,0 10,10 10,10 0,0 0)))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    if not g1.HasCurveGeometry():
        gdaltest.post_reason('fail')
        return 'fail'
    if g1.HasCurveGeometry(True):
        gdaltest.post_reason('fail')
        return 'fail'

    # WKT with all possible sub geometries
    in_wkt = 'MULTISURFACE (((0 0,0 10,10 10,10 0,0 0)),CURVEPOLYGON (CIRCULARSTRING (0 0,1 0,0 0)))'
    g1 = ogr.CreateGeometryFromWkt(in_wkt)
    out_wkt = g1.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    g2 = ogr.CreateGeometryFromWkb(g1.ExportToWkb())
    out_wkt = g2.ExportToWkt()
    if in_wkt != out_wkt:
        gdaltest.post_reason('fail')
        print(out_wkt)
        return 'fail'

    # Test ForceToMultiPolygon
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', '45')
    g2 = ogr.ForceToMultiPolygon(g1)
    gdal.SetConfigOption('OGR_ARC_STEPSIZE', None)
    expected_g = 'MULTIPOLYGON (((0 0,0 10,10 10,10 0,0 0)),((0 0,0.116977778440514 -0.321393804843282,0.413175911166547 -0.49240387650611,0.75 -0.433012701892224,0.969846310392967 -0.171010071662835,0.969846310392967 0.171010071662835,0.75 0.433012701892224,0.413175911166547 0.49240387650611,0.116977778440514 0.321393804843282,0 0)))'
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'

    # Test GetLinearGeometry
    g2 = g1.GetLinearGeometry(45)
    if ogrtest.check_feature_geometry(g2, expected_g) != 0:
        gdaltest.post_reason('fail')
        print(g2)
        return 'fail'
    # Check that GetLinearGeometry() is idem-potent on MULTIPOLYGON
    g3 = g2.GetLinearGeometry(45)
    if not g3.Equals(g2):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # PointOnSurface
    if ogrtest.have_geos():
        in_wkt = 'MULTISURFACE (((0 0,0 10,10 10,10 0,0 0),(1 1,1 9,9 9,9 1,1 1)),((10 0,10 10,20 10,20 0,10 0),(11 1,11 9,19 9,19 1,11 1)))'
        g1 = ogr.CreateGeometryFromWkt(in_wkt)
        p1 = g1.PointOnSurface()
        if p1.ExportToWkt() != 'POINT (0.5 5.0)':
            gdaltest.post_reason('fail')
            print(p1)
            return 'fail'

    # Error case : wrong sub-geometry type
    in_wkt = 'MULTIPOLYGON (POINT EMPTY)'
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    g = ogr.CreateGeometryFromWkt(in_wkt)
    gdal.PopErrorHandler()
    if g is not None:
        gdaltest.post_reason('fail')
        return 'fail'

    return 'success'

###############################################################################
# Test GetCurveGeometry


def ogr_geom_getcurvegeometry():

    for geom in ['POINT', 'LINESTRING', 'POLYGON', 'MULTIPOINT', 'MULTILINESTRING',
                 'MULTIPOLYGON', 'GEOMETRYCOLLECTION',
                 'CIRCULARSTRING',
                 'COMPOUNDCURVE',
                 'CURVEPOLYGON',
                 'MULTICURVE',
                 'MULTISURFACE']:
        in_wkt = geom + ' EMPTY'
        g = ogr.CreateGeometryFromWkt(in_wkt)
        g2 = g.GetCurveGeometry()
        if g2.ExportToWkt() != in_wkt:
            gdaltest.post_reason('fail')
            print(g)
            print(g2)
            return 'fail'

    g = ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION(POINT (0 1))')
    g2 = g.GetCurveGeometry()
    if not g.Equals(g2):
        gdaltest.post_reason('fail')
        return 'fail'

    g = ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION(LINESTRING (0 0,0 1,0 0))')
    g2 = g.GetCurveGeometry()
    if not g.Equals(g2):
        gdaltest.post_reason('fail')
        return 'fail'

    g = ogr.CreateGeometryFromWkt('POLYGON((0 0,0 1,1 1,1 0,0 0))')
    g2 = g.GetCurveGeometry()
    if not g.Equals(g2):
        gdaltest.post_reason('fail')
        return 'fail'

    g = ogr.CreateGeometryFromWkt('POLYGON Z ((0 0 10,0 1 10,1 1 10,1 0 10,0 0 10))')
    g2 = g.GetCurveGeometry()
    if not g.Equals(g2):
        gdaltest.post_reason('fail')
        return 'fail'

    # CircularString with large step
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,1 1,2 0)')
    g2 = g1.GetLinearGeometry(15)
    g3 = g2.GetCurveGeometry()
    if g3.GetGeometryType() != ogr.wkbCircularString or \
       g1.GetPoint(0) != g3.GetPoint(0) or g1.GetPoint(2) != g3.GetPoint(2) or \
       abs((g3.GetX(1) - 1) * (g3.GetX(1) - 1) + g3.GetY(1) * g3.GetY(1) - 1) > 1e-8:
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # CurvePolygon with large step
    g1 = ogr.CreateGeometryFromWkt('CURVEPOLYGON( CIRCULARSTRING (0 0,1 1,0 0))')
    g2 = g1.GetLinearGeometry(15)
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # This is a straight line
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (1 2,3 4,5 6)')
    g2 = g1.GetLinearGeometry()
    g3 = g2.GetCurveGeometry()
    if g3.ExportToWkt() != 'LINESTRING (1 2,3 4,5 6)':
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # "Random" arcs
    for wkt in ['CIRCULARSTRING (1 2,3 1,5 6)',
                'CIRCULARSTRING (1 -2,3 -1,5 -6)',
                'CIRCULARSTRING (-1 2,-3 1,-5 6)',
                'CIRCULARSTRING (5 6,3 1,1 2)',
                'CIRCULARSTRING (-5 6,-3 1,-1 2)',
                'CIRCULARSTRING (5 -6,3 -1,1 -2)',
                'CIRCULARSTRING (215725 -977513,872751 872597,560240 -7500)',
                'CIRCULARSTRING (-492367 816163,537838 -421954,745494 -65479)',
                'CIRCULARSTRING (543208 -865295,582257 635396,563925 -68156)',
                'CIRCULARSTRING (-481 -193,1 329,-692 -421)',
                'CIRCULARSTRING (525407 781005,710737 463833,-674365 340022)',
                'CIRCULARSTRING (743949 709309,743952 709307,743964 709298)',
                'CIRCULARSTRING (283167 -48388,536492 -197399,-449301 382451)']:
        g1 = ogr.CreateGeometryFromWkt(wkt)
        g2 = g1.GetLinearGeometry()
        g3 = g2.GetCurveGeometry()
        if not g3.Equals(g1):
            gdaltest.post_reason('fail')
            print(g1)
            print(g3)
            return 'fail'

    # Really random arcs with coordinates in the [-1000,1000] range
    for i in range(1000):
        v = [random.randint(-1000, 1000) for i in range(6)]
        if v[0] != v[4] or v[1] != v[5]:
            wkt = 'CIRCULARSTRING (%d %d,%d %d,%d %d)' % (v[0], v[1], v[2], v[3], v[4], v[5])
            g1 = ogr.CreateGeometryFromWkt(wkt)
            g2 = g1.GetLinearGeometry()
            if g2.GetPointCount() != 3:
                g3 = g2.GetCurveGeometry()
                if not g3.Equals(g1):
                    # FIXME sometime... but avoid failing. for now. This randomly fails, but this is not
                    # the end of the world...
                    # gdaltest.post_reason('fail')
                    print('Difference found :')
                    print(g1)
                    print(g3)
                    # return 'fail'

    # Really random arcs in random displacements, but with small radius
    for i in range(1000):
        x = random.randint(-1000000, 1000000)
        y = random.randint(-1000000, 1000000)
        v = [random.randint(-10, 10) for i in range(6)]
        if v[0] != v[4] or v[1] != v[5]:
            wkt = 'CIRCULARSTRING (%d %d,%d %d,%d %d)' % (x + v[0], y + v[1], x + v[2], y + v[3], x + v[4], y + v[5])
            g1 = ogr.CreateGeometryFromWkt(wkt)
            g2 = g1.GetLinearGeometry()
            if g2.GetPointCount() != 3:
                g3 = g2.GetCurveGeometry()
                if not g3.Equals(g1):
                    # FIXME sometime... but avoid failing. for now. This randomly fails, but this is not
                    # the end of the world...
                    # gdaltest.post_reason('fail')
                    print('Difference found :')
                    print(g1)
                    print(g3)
                    # return 'fail'

    # Really random arcs with coordinates in the [-1000000,1000000] range
    for i in range(1000):
        v = [random.randint(-1000000, 1000000) for i in range(6)]
        if v[0] != v[4] or v[1] != v[5]:
            wkt = 'CIRCULARSTRING (%d %d,%d %d,%d %d)' % (v[0], v[1], v[2], v[3], v[4], v[5])
            g1 = ogr.CreateGeometryFromWkt(wkt)
            g2 = g1.GetLinearGeometry()
            if g2.GetPointCount() != 3:
                g3 = g2.GetCurveGeometry()
                if not g3.Equals(g1):
                    # FIXME sometime... but avoid failing. for now. This randomly fails, but this is not
                    # the end of the world...
                    # gdaltest.post_reason('fail')
                    print('Difference found :')
                    print(g1)
                    print(g3)
                    # return 'fail'

    # 5 points full circle
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,0.5 -0.5,1 0,0.5 0.5,0 0)')
    g2 = g1.GetLinearGeometry()
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # 3 points full circle
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,1 0,0 0)')
    g2 = g1.GetLinearGeometry()
    g3 = g2.GetCurveGeometry()
    if g3.GetGeometryType() != ogr.wkbCircularString or \
       g1.GetPoint(0) != g3.GetPoint(0) or \
       g1.GetPoint(1) != g3.GetPoint(2) or \
       g1.GetPoint(2) != g3.GetPoint(4) or \
       abs((g3.GetX(1) - 0.5) * (g3.GetX(1) - 0.5) + g3.GetY(1) * g3.GetY(1) - 0.5 * 0.5) > 1e-12 or \
       abs((g3.GetX(3) - 0.5) * (g3.GetX(3) - 0.5) + g3.GetY(3) * g3.GetY(3) - 0.5 * 0.5) > 1e-12:
        gdaltest.post_reason('fail')
        print(g3)
        # print(abs((g3.GetX(1) - 0.5)*(g3.GetX(1) - 0.5)+g3.GetY(1)*g3.GetY(1) - 0.5*0.5))
        # print(abs((g3.GetX(3) - 0.5)*(g3.GetX(3) - 0.5)+g3.GetY(3)*g3.GetY(3) - 0.5*0.5))
        return 'fail'

    # 3 points full circle in a CurvePolygon
    for wkt in ['CURVEPOLYGON( CIRCULARSTRING (0 0,1 0,0 0))',
                'CURVEPOLYGON( CIRCULARSTRING (0 0,0 1,0 0))',
                'CURVEPOLYGON( CIRCULARSTRING (0 0,-1 0,0 0))',
                'CURVEPOLYGON( CIRCULARSTRING (0 0,0 -1,0 0))']:
        g1 = ogr.CreateGeometryFromWkt(wkt)
        g2 = g1.GetLinearGeometry()
        g3 = g2.GetCurveGeometry()
        if not g3.Equals(g1):
            gdaltest.post_reason('fail')
            print(g1)
            print(g3)
            return 'fail'

    # 2 curves in the CircularString
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,1 1,2 0,3 -1,4 0)')
    g2 = g1.GetLinearGeometry()
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # 3 curves in the CircularString
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,1 1,2 0,3 -1,4 0,5 1,6 0)')
    g2 = g1.GetLinearGeometry()
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # CircularString, LineString, CircularString
    g1 = ogr.CreateGeometryFromWkt('COMPOUNDCURVE (CIRCULARSTRING (0 0,1 1,2 0),(2 0,3 0,4 0),CIRCULARSTRING (4 0,5 1,6 0))')
    g2 = g1.GetLinearGeometry()
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # LineString, CircularString, LineString, CircularString, LineString
    g1 = ogr.CreateGeometryFromWkt('COMPOUNDCURVE ((-1 0,-0.5 0.5,0 0),CIRCULARSTRING (0 0,1 1,2 0),(2 0,3 0,4 0),CIRCULARSTRING (4 0,5 1,6 0),(6 0,7 0))')
    g2 = g1.GetLinearGeometry()
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # Check with default discretization method
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,1.2 1.0,2 0)')
    g2 = ogr.CreateGeometryFromWkt('LINESTRING (0 0,0.000997093138961 0.068920262501281,0.006738548124866 0.137608197923873,0.017197098230267 0.205737600590167,0.032323074784779 0.272984917348872,0.052044643056421 0.339030784160355,0.076268143401735 0.403561542787492,0.104878536064531 0.466270730389102,0.137739947510866 0.526860534941749,0.174696315705653 0.585043209577972,0.215572131266425 0.640542439124111,0.260173270974444 0.693094652347904,0.30828791968472 0.742450273683876,0.359687576256715 0.788374908491942,0.414128138728451 0.830650456220319,0.471351063580441 0.869076146186235,0.531084593583979 0.903469491055406,0.593045048402615 0.933667153492107,0.656938171817632 0.959525721864054,0.722460529179411 0.980922391318168,0.789300948448056 0.99775554699276,0.857141997979641 1.009945246596371,0.925661494039921 1.017433600061489,0.994534030886182 1.020185044470095,1.063432526150724 1.01818651294542,1.132029774186796 1.01144749670781,1.2 1.0,1.267547127648721 0.983752320094182,1.333803428245673 0.962854851656094,1.398449236893265 0.937408418110045,1.461172658788815 0.907535790143504,1.521671074014578 0.873381093378847,1.579652597579492 0.835109113014538,1.634837487668428 0.792904498790658,1.686959495304612 0.746970874114522,1.73576714891352 0.697529853644598,1.781024967590663 0.644819974072535,1.822514597219645 0.589095543261942,1.860035863959079 0.53062541329644,1.89340774001566 0.469691683356621,1.922469217043826 0.406588338684124,1.94708008295817 0.341619832199361,1.967121598410718 0.27509961561613,1.982497069669296 0.207348627140011,1.993132315133044 0.138693743046887,1.998976023234287 0.069466200612231,2 0)')
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # Check with alternate discretization method : ROUND_ANGLE_METHOD
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,1.2 1.0,2 0)')
    g2 = ogr.CreateGeometryFromWkt('LINESTRING (0 0,-0.000199980003999 0.02,0.002236456877416 0.089770423644023,0.009533897446083 0.159200932797352,0.021656789305088 0.227953268998521,0.038546070943884 0.295692477776518,0.060119459480029 0.362088540515299,0.086271851533127 0.426817982271309,0.116875835277923 0.489565447710894,0.151782311181914 0.550025237489786,0.190821218403283 0.607902797589577,0.233802363310224 0.662916154355295,0.280516346085201 0.7147972882427,0.330735580899807 0.763293439582565,0.384215404690045 0.80816834000038,0.440695269130182 0.849203363492117,0.499900009998002 0.886198591548151,0.561541187747236 0.918973787136141,0.62531849275604 0.947369272797732,0.690921208405283 0.971246708581086,0.758029724858684 0.990489766019218,0.826317096169807 1.005004694870594,0.895450633129846 1.014720779860886,0.965093524096011 1.019590685200679,1.034906475903993 1.019590685200679,1.104549366870158 1.014720779860886,1.173682903830197 1.005004694870593,1.2 1.0,1.241970275141317 0.990489766019217,1.309078791594718 0.971246708581085,1.374681507243961 0.947369272797731,1.438458812252765 0.91897378713614,1.500099990002 0.886198591548151,1.559304730869819 0.849203363492116,1.615784595309956 0.808168340000379,1.669264419100194 0.763293439582565,1.7194836539148 0.714797288242699,1.766197636689777 0.662916154355294,1.809178781596718 0.607902797589576,1.848217688818087 0.550025237489785,1.883124164722078 0.489565447710893,1.913728148466874 0.426817982271308,1.939880540519971 0.362088540515298,1.961453929056117 0.295692477776516,1.978343210694912 0.227953268998519,1.990466102553917 0.15920093279735,1.997763543122584 0.089770423644022,2.000199980003999 0.02,2 0)')
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # Check with PostgreSQL output of SELECT ST_CurveToLine(ST_GeomFromText('CIRCULARSTRING (0 0,1.2 1.0,2 0)'))
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,1.2 1.0,2 0)')
    g2 = ogr.CreateGeometryFromWkt('LINESTRING (0 0,0.000223190308279 0.049091765203314,0.002854930521212 0.098113445796116,0.007888880546112 0.146946944256066,0.015312913156447 0.195474616408063,0.025109143207391 0.243579554839372,0.037253970722702 0.291145870539817,0.051718137749134 0.338058972088558,0.068466798841411 0.384205841714863,0.08745960500795 0.429475307567812,0.108650800915124 0.473758311539029,0.131989335115863 0.516948171993215,0.157418983037062 0.558940840773549,0.184878482429505 0.599635153862819,0.214301680953989 0.638933075096389,0.245617695548099 0.676739932339917,0.27875108318972 0.712964645562815,0.31362202264588 0.747519946258017,0.350146506769097 0.780322587679462,0.388236544877951 0.811293545390794,0.427800374734344 0.840358207642151,0.46874268360677 0.867446555116406,0.510964837887032 0.892493329611833,0.554365120707246 0.915438191254836,0.598838976984681 0.936225863863983,0.644279265304116 0.954806268115175,0.690576516030889 0.971134642187118,0.737619195032841 0.985171649596477,0.785293972375802 0.996883473962907,0.833485995345338 1.006241900475673,0.88207916513699 1.013224383865605,0.930956416548473 1.017814102718623,0.98 1.02,1.029091765203309 1.019776809691721,1.078113445796111 1.017145069478788,1.12694694425606 1.012111119453889,1.175474616408058 1.004687086843554,1.223579554839367 0.994890856792611,1.271145870539812 0.9827460292773,1.318058972088553 0.968281862250867,1.364205841714858 0.951533201158591,1.409475307567807 0.932540394992052,1.453758311539024 0.911349199084878,1.49694817199321 0.88801066488414,1.538940840773545 0.862581016962941,1.579635153862814 0.835121517570498,1.618933075096384 0.805698319046015,1.656739932339913 0.774382304451905,1.692964645562811 0.741248916810284,1.727519946258013 0.706377977354124,1.760322587679458 0.669853493230907,1.791293545390791 0.631763455122053,1.820358207642148 0.59219962526566,1.847446555116403 0.551257316393235,1.872493329611831 0.509035162112973,1.895438191254833 0.465634879292759,1.916225863863981 0.421161023015324,1.934806268115173 0.37572073469589,1.951134642187117 0.329423483969116,1.965171649596476 0.282380804967164,1.976883473962906 0.234706027624203,1.986241900475672 0.186514004654668,1.993224383865604 0.137920834863015,1.997814102718623 0.089043583451532,2.0 0.04,2 0)')
    g3 = g2.GetCurveGeometry()
    g1_expected = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,0.98 1.02,2 0)')
    if not g3.Equals(g1_expected):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # Test default ( implicit option ADD_INTERMEDIATE_POINT=STEALTH )
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,1.2 1.0,2 0)')
    g2 = g1.GetLinearGeometry()
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # Test with Z
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0 1,1 1 2,2 0 3)')
    g2 = g1.GetLinearGeometry()
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (2 0 3,1 1 2,0 0 1)')
    g2 = g1.GetLinearGeometry()
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # Test option ADD_INTERMEDIATE_POINT=STEALTH
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,1.2 1.0,2 0)')
    g2 = g1.GetLinearGeometry(options=['ADD_INTERMEDIATE_POINT=STEALTH'])
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # Test option ADD_INTERMEDIATE_POINT=YES
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,1.2 1.0,2 0)')
    g2 = g1.GetLinearGeometry(options=['ADD_INTERMEDIATE_POINT=YES'])
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # Test with big coordinates. The points are (2,49),(3,50),(4,49) reprojected from EPSG:4326 to EPSG:32631
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (426857.987717275 5427937.52346616,500000.000000001 5538630.70286887,573142.012282726 5427937.52346616)')
    g2 = g1.GetLinearGeometry()
    g3 = g2.GetCurveGeometry()
    if ogrtest.check_feature_geometry(g3, g1) != 0:
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # Same with integer coordinates
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (426858 5427938,500000 5538632,573142 5427938)')
    g2 = g1.GetLinearGeometry()
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # Test option ADD_INTERMEDIATE_POINT=FALSE
    g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,1.2 1.0,2 0)')
    g2 = g1.GetLinearGeometry(options=['ADD_INTERMEDIATE_POINT=FALSE'])
    g3 = g2.GetCurveGeometry()
    g1_expected = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,1.0 1.020199980003999,2 0)')
    if ogrtest.check_feature_geometry(g3, g1_expected) != 0:
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # Test with unrecognized options
    gdal.PushErrorHandler('CPLQuietErrorHandler')
    g2_new = g1.GetLinearGeometry(options=['bla', 'ADD_INTERMEDIATE_POINT=FALSE', 'foo=bar'])
    gdal.PopErrorHandler()
    if not g2_new.Equals(g2):
        gdaltest.post_reason('fail')
        print(g2_new)
        return 'fail'

    # Add repeated point at end of line
    g2 = g1.GetLinearGeometry()
    g2.AddPoint_2D(2 - 1e-9, 0)
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # Add repeated point at end of line
    g2 = g1.GetLinearGeometry()
    g2_new = ogr.Geometry(ogr.wkbLineString)
    g2_new.AddPoint_2D(0, 1e-9)
    for i in range(g2.GetPointCount()):
        g2_new.AddPoint_2D(g2.GetX(i), g2.GetY(i))
    g3 = g2_new.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # Test various configurations
    for (wkt, eps) in [('CIRCULARSTRING (0 0,0.5 0.5,0 1,-0.5 0.5,0 0)', 0),
                       ('CIRCULARSTRING (0 0,-0.5 0.5,0 1,0.5 0.5,0 0)', 0),
                       ('CIRCULARSTRING (0 0,0.5 -0.5,0 -1,-0.5 -0.5,0 0)', 0),
                       ('CIRCULARSTRING (0 0,-0.5 -0.5,0 -1,0.5 -0.5,0 0)', 0),
                       ('CIRCULARSTRING (-1 -1,-1 1,1 1,1 -1,-1 -1)', 0),
                       ('CIRCULARSTRING (-1 -1,1 -1,1 1,-1 1,-1 -1)', 0),
                       ('CIRCULARSTRING (0 1,1 0,0 -1,-1 0,0 1)', 0),
                       ('CIRCULARSTRING (0 0.01,0.01 0,0 -0.01,-0.01 0,0 0.01)', 0),
                       ('CIRCULARSTRING (0 0.0001,0.0001 0,0 -0.0001,-0.0001 0,0 0.0001)', 0),
                       ('CIRCULARSTRING (0 1000000,1000000 0,0 -1000000,-1000000 0,0 1000000)', 0),
                       ('CIRCULARSTRING (1234567 8901234,5678901 23456789,0123456 78901234)', 0),
                       ('CIRCULARSTRING (1234567.12 8901234.34,5678901.56 23456789.01,0123456.78 78901234.56)', 1e-1),
                       ('CIRCULARSTRING (1234567 -8901234,-5678901 23456789,0123456 -78901234)', 0),
                       ('CIRCULARSTRING (0 0.000001,0.000001 0,0 -0.000001,-0.000001 0,0 0.000001)', 1e-12),
                       ('CIRCULARSTRING (0 0.00000001,0.00000001 0,0 -0.00000001,-0.00000001 0,0 0.00000001)', 1e-12),
                       ('CIRCULARSTRING (1 0.00000001,1.00000001 0,1 -0.00000001,0.99999999 0,1 0.00000001)', 1e-12),
                       ('CIRCULARSTRING (100000000 1,100000001 0,100000000 -1,99999999 0,100000000 1)', 0),
                       ('CIRCULARSTRING (-100000000 1,-100000001 0,-100000000 -1,-99999999 0,-100000000 1)', 0),
                       ('CIRCULARSTRING (100000000 100000001,100000001 100000000,100000000 99999999,99999999 100000000,100000000 100000001)', 0),
                       ('CIRCULARSTRING (760112.098000001162291 207740.096999999135733,760116.642489952617325 207741.101843414857285,760120.967999998480082 207742.820000000298023,760123.571822694852017 207744.275888498465065,760126.011999998241663 207745.991999998688698,760127.330062366439961 207747.037052432337077,760128.585999999195337 207748.155999999493361)', 1e-5)]:
        g1 = ogr.CreateGeometryFromWkt(wkt)
        g2 = g1.GetLinearGeometry()
        g3 = g2.GetCurveGeometry()
        if (eps == 0 and not g3.Equals(g1)) or (eps > 0 and ogrtest.check_feature_geometry(g3, g1, eps) != 0):
            gdaltest.post_reason('fail')
            print('')
            print(g1)
            print(g3)
            print(ogrtest.check_feature_geometry(g3, g1, 1e-6))
            return 'fail'

    # Test with GEOMETRYCOLLECTION container
    g1 = ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION(CIRCULARSTRING (0 0,0.5 0.5,0 1,-0.5 0.5,0 0))')
    g2 = g1.GetLinearGeometry()
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # Test with MULTICURVE container
    g1 = ogr.CreateGeometryFromWkt('MULTICURVE(CIRCULARSTRING (0 0,0.5 0.5,0 1,-0.5 0.5,0 0))')
    g2 = g1.GetLinearGeometry()
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    # Test with MULTISURFACE container
    g1 = ogr.CreateGeometryFromWkt('MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING (0 0,0.5 0.5,1 0),(1 0,0 0))))')
    g2 = g1.GetLinearGeometry()
    g3 = g2.GetCurveGeometry()
    if not g3.Equals(g1):
        gdaltest.post_reason('fail')
        print(g3)
        return 'fail'

    if ogrtest.have_geos():
        g1 = ogr.CreateGeometryFromWkt('CURVEPOLYGON(CIRCULARSTRING (0 0,2 0,0 0))')
        g2 = ogr.CreateGeometryFromWkt('CURVEPOLYGON(CIRCULARSTRING (1 0,3 1,1 0))')
        g3 = g1.Intersection(g2)
        if g3.GetGeometryType() != ogr.wkbCurvePolygon:
            gdaltest.post_reason('fail')
            print(g3)
            return 'fail'

        g1 = ogr.CreateGeometryFromWkt('CURVEPOLYGON(CIRCULARSTRING (0 0,2 0,0 0))')
        g2 = ogr.CreateGeometryFromWkt('CURVEPOLYGON((1 -1,1 1,3 1,3 -1,1 -1))')
        g3 = g1.Intersection(g2)
        if g3.GetGeometryType() != ogr.wkbCurvePolygon:
            gdaltest.post_reason('fail')
            print(g3)
            return 'fail'

        g1 = ogr.CreateGeometryFromWkt('CURVEPOLYGON(CIRCULARSTRING (0 0,2 0,0 0))')
        g2 = ogr.CreateGeometryFromWkt('CURVEPOLYGON(CIRCULARSTRING (3 0,5 0,3 0))')
        g3 = g1.Union(g2)
        if g3.ExportToWkt() != 'MULTISURFACE (CURVEPOLYGON (CIRCULARSTRING (0 0,2 0,0 0)),CURVEPOLYGON (CIRCULARSTRING (3 0,5 0,3 0)))':
            gdaltest.post_reason('fail')
            print(g3)
            return 'fail'

        g1 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (0 0,1 1,2 0))')
        g2 = ogr.CreateGeometryFromWkt('CIRCULARSTRING (2 0,1 -1,0 0))')
        g3 = g1.Union(g2)
        if g3.ExportToWkt() != 'MULTICURVE (CIRCULARSTRING (0 0,1 1,2 0),CIRCULARSTRING (2 0,1 -1,0 0))':
            gdaltest.post_reason('fail')
            print(g3)
            return 'fail'

        g1 = ogr.CreateGeometryFromWkt('POINT(1 2)')
        g1 = g1.Buffer(0.5)
        g1 = g1.GetCurveGeometry()
        if g1.ExportToWkt() != 'CURVEPOLYGON (CIRCULARSTRING (1.5 2.0,0.5 2.0,1.5 2.0))':
            gdaltest.post_reason('fail')
            print(g1)
            return 'fail'

    return 'success'

###############################################################################
# Test OGR_GT_ functions


def ogr_geom_gt_functions():

    # GT_HasZ
    tuples = [(ogr.wkbPoint, 0),
              (ogr.wkbPoint25D, 1),
              (ogr.wkbPointM, 0),
              (ogr.wkbPointZM, 1),
              (ogr.wkbCircularString, 0),
              (ogr.wkbCircularStringZ, 1),
              (ogr.wkbCircularStringM, 0),
              (ogr.wkbCircularStringZM, 1)]
    for (gt, res) in tuples:
        if ogr.GT_HasZ(gt) != res:
            gdaltest.post_reason('fail')
            print(gt)
            return 'fail'

    # GT_SetZ
    tuples = [(ogr.wkbPoint, ogr.wkbPoint25D),
              (ogr.wkbPoint25D, ogr.wkbPoint25D),
              (ogr.wkbPointM, ogr.wkbPointZM),
              (ogr.wkbPointZM, ogr.wkbPointZM),
              (ogr.wkbCircularString, ogr.wkbCircularStringZ),
              (ogr.wkbCircularStringZ, ogr.wkbCircularStringZ),
              (ogr.wkbCircularStringM, ogr.wkbCircularStringZM),
              (ogr.wkbCircularStringZM, ogr.wkbCircularStringZM)]
    for (gt, res) in tuples:
        if ogr.GT_SetZ(gt) != res:
            gdaltest.post_reason('fail')
            print(gt)
            return 'fail'

    # GT_HasM
    tuples = [(ogr.wkbPoint, 0),
              (ogr.wkbPoint25D, 0),
              (ogr.wkbPointM, 1),
              (ogr.wkbPointZM, 1),
              (ogr.wkbCircularString, 0),
              (ogr.wkbCircularStringZ, 0),
              (ogr.wkbCircularStringM, 1),
              (ogr.wkbCircularStringZM, 1)]
    for (gt, res) in tuples:
        if ogr.GT_HasM(gt) != res:
            gdaltest.post_reason('fail')
            print(gt)
            return 'fail'

    # GT_SetM
    tuples = [(ogr.wkbPoint, ogr.wkbPointM),
              (ogr.wkbPoint25D, ogr.wkbPointZM),
              (ogr.wkbPointM, ogr.wkbPointM),
              (ogr.wkbPointZM, ogr.wkbPointZM),
              (ogr.wkbCircularString, ogr.wkbCircularStringM),
              (ogr.wkbCircularStringZ, ogr.wkbCircularStringZM),
              (ogr.wkbCircularStringM, ogr.wkbCircularStringM),
              (ogr.wkbCircularStringZM, ogr.wkbCircularStringZM)]
    for (gt, res) in tuples:
        if ogr.GT_SetM(gt) != res:
            gdaltest.post_reason('fail')
            print(gt)
            return 'fail'

    # OGR_GT_SetModifier
    tuples = [(ogr.wkbPoint, 0, 0, ogr.wkbPoint),
              (ogr.wkbPoint, 1, 0, ogr.wkbPoint25D),
              (ogr.wkbPoint, 0, 1, ogr.wkbPointM),
              (ogr.wkbPoint, 1, 1, ogr.wkbPointZM),
              (ogr.wkbPoint25D, 0, 0, ogr.wkbPoint),
              (ogr.wkbPoint25D, 1, 0, ogr.wkbPoint25D),
              (ogr.wkbPoint25D, 0, 1, ogr.wkbPointM),
              (ogr.wkbPoint25D, 1, 1, ogr.wkbPointZM),
              (ogr.wkbPointM, 0, 0, ogr.wkbPoint),
              (ogr.wkbPointM, 1, 0, ogr.wkbPoint25D),
              (ogr.wkbPointM, 0, 1, ogr.wkbPointM),
              (ogr.wkbPointM, 1, 1, ogr.wkbPointZM),
              (ogr.wkbCircularString, 1, 0, ogr.wkbCircularStringZ),
              (ogr.wkbCircularStringZ, 1, 0, ogr.wkbCircularStringZ),
              (ogr.wkbPoint, 0, 0, ogr.wkbPoint),
              (ogr.wkbPoint25D, 0, 0, ogr.wkbPoint),
              (ogr.wkbCircularString, 0, 0, ogr.wkbCircularString),
              (ogr.wkbCircularStringZ, 0, 0, ogr.wkbCircularString)]
    for (gt, modZ, modM, res) in tuples:
        if ogr.GT_SetModifier(gt, modZ, modM) != res:
            gdaltest.post_reason('fail')
            print(gt)
            return 'fail'

    # GT_Flatten
    tuples = [(ogr.wkbPoint, ogr.wkbPoint),
              (ogr.wkbPoint25D, ogr.wkbPoint),
              (ogr.wkbPointM, ogr.wkbPoint),
              (ogr.wkbPointZM, ogr.wkbPoint),
              (ogr.wkbCircularString, ogr.wkbCircularString),
              (ogr.wkbTriangleZ, ogr.wkbTriangle),
              (ogr.wkbCircularStringZ, ogr.wkbCircularString),
              (ogr.wkbCircularStringM, ogr.wkbCircularString),
              (ogr.wkbCircularStringZM, ogr.wkbCircularString)]
    for (gt, res) in tuples:
        if ogr.GT_Flatten(gt) != res:
            gdaltest.post_reason('fail')
            print(gt)
            return 'fail'

    # GT_IsSubClassOf
    tuples = [(ogr.wkbPoint, ogr.wkbPoint, 1),
              (ogr.wkbPoint25D, ogr.wkbPoint, 1),
              (ogr.wkbPoint, ogr.wkbUnknown, 1),
              (ogr.wkbPoint, ogr.wkbLineString, 0),
              (ogr.wkbPolygon, ogr.wkbCurvePolygon, 1),
              (ogr.wkbTriangle, ogr.wkbCurvePolygon, 1),
              (ogr.wkbTriangle, ogr.wkbPolygon, 1),
              (ogr.wkbMultiSurface, ogr.wkbGeometryCollection, 1),
              (ogr.wkbMultiPolygon, ogr.wkbMultiSurface, 1),
              (ogr.wkbMultiLineString, ogr.wkbMultiCurve, 1),
              (ogr.wkbUnknown, ogr.wkbUnknown, 1),
              (ogr.wkbUnknown, ogr.wkbPoint, 0),
              (ogr.wkbTIN, ogr.wkbPolyhedralSurface, 1),
              (ogr.wkbPolyhedralSurface, ogr.wkbTIN, 0),
              ]
    for (gt, gt2, res) in tuples:
        if ogr.GT_IsSubClassOf(gt, gt2) != res:
            gdaltest.post_reason('fail')
            print(gt)
            print(gt2)
            return 'fail'

    # GT_IsCurve
    tuples = [(ogr.wkbPoint, 0),
              (ogr.wkbPoint25D, 0),
              (ogr.wkbPointM, 0),
              (ogr.wkbPointZM, 0),
              (ogr.wkbCircularString, 1),
              (ogr.wkbCircularStringZ, 1),
              (ogr.wkbLineString, 1),
              (ogr.wkbCompoundCurve, 1),
              (ogr.wkbCompoundCurveZ, 1),
              (ogr.wkbCompoundCurveM, 1),
              (ogr.wkbCompoundCurveZM, 1),
              (ogr.wkbCurvePolygon, 0),
              (ogr.wkbTriangle, 0),
              (ogr.wkbPolyhedralSurface, 0),
              (ogr.wkbTIN, 0)]
    for (gt, res) in tuples:
        if ogr.GT_IsCurve(gt) != res:
            gdaltest.post_reason('fail')
            print(gt)
            return 'fail'

    # GT_IsSurface
    tuples = [(ogr.wkbPoint, 0),
              (ogr.wkbPoint25D, 0),
              (ogr.wkbPointM, 0),
              (ogr.wkbPointZM, 0),
              (ogr.wkbCircularString, 0),
              (ogr.wkbCurvePolygon, 1),
              (ogr.wkbCurvePolygonZ, 1),
              (ogr.wkbCurvePolygonM, 1),
              (ogr.wkbCurvePolygonZM, 1),
              (ogr.wkbPolygon, 1),
              (ogr.wkbTriangle, 1),
              (ogr.wkbPolyhedralSurface, 1),
              (ogr.wkbTIN, 1)]
    for (gt, res) in tuples:
        if ogr.GT_IsSurface(gt) != res:
            gdaltest.post_reason('fail')
            print(gt)
            return 'fail'

    # GT_GetCollection
    tuples = [(ogr.wkbPoint, ogr.wkbMultiPoint),
              (ogr.wkbPoint25D, ogr.wkbMultiPoint25D),
              (ogr.wkbPointM, ogr.wkbMultiPointM),
              (ogr.wkbPointZM, ogr.wkbMultiPointZM),
              (ogr.wkbCircularString, ogr.wkbMultiCurve),
              (ogr.wkbCompoundCurve, ogr.wkbMultiCurve),
              (ogr.wkbCurvePolygon, ogr.wkbMultiSurface),
              (ogr.wkbLineString, ogr.wkbMultiLineString),
              (ogr.wkbPolygon, ogr.wkbMultiPolygon)]
    for (gt, res) in tuples:
        if ogr.GT_GetCollection(gt) != res:
            gdaltest.post_reason('fail')
            print(gt)
            return 'fail'

    # GT_IsNonLinear
    tuples = [(ogr.wkbPoint, 0),
              (ogr.wkbPoint25D, 0),
              (ogr.wkbPointM, 0),
              (ogr.wkbPointZM, 0),
              (ogr.wkbCircularString, 1),
              (ogr.wkbCircularStringM, 1),
              (ogr.wkbCircularStringZ, 1),
              (ogr.wkbCircularStringZM, 1),
              (ogr.wkbCompoundCurve, 1),
              (ogr.wkbCurvePolygon, 1),
              (ogr.wkbMultiCurve, 1),
              (ogr.wkbMultiSurface, 1),
              (ogr.wkbLineString, 0),
              (ogr.wkbPolygon, 0),
              (ogr.wkbTriangle, 0)]
    for (gt, res) in tuples:
        if ogr.GT_IsNonLinear(gt) != res:
            gdaltest.post_reason('fail')
            print(gt)
            return 'fail'

    # GT_GetCurve
    tuples = [(ogr.wkbPoint, ogr.wkbPoint),
              (ogr.wkbPoint25D, ogr.wkbPoint25D),
              (ogr.wkbPointM, ogr.wkbPointM),
              (ogr.wkbPointZM, ogr.wkbPointZM),
              (ogr.wkbCircularString, ogr.wkbCircularString),
              (ogr.wkbCircularStringZ, ogr.wkbCircularStringZ),
              (ogr.wkbCircularStringM, ogr.wkbCircularStringM),
              (ogr.wkbCircularStringZM, ogr.wkbCircularStringZM),
              (ogr.wkbCompoundCurve, ogr.wkbCompoundCurve),
              (ogr.wkbCurvePolygon, ogr.wkbCurvePolygon),
              (ogr.wkbLineString, ogr.wkbCompoundCurve),
              (ogr.wkbPolygon, ogr.wkbCurvePolygon),
              (ogr.wkbMultiLineString, ogr.wkbMultiCurve),
              (ogr.wkbMultiPolygon, ogr.wkbMultiSurface),
              (ogr.wkbMultiCurve, ogr.wkbMultiCurve),
              (ogr.wkbMultiSurface, ogr.wkbMultiSurface)]
    for (gt, res) in tuples:
        if ogr.GT_GetCurve(gt) != res:
            gdaltest.post_reason('fail')
            print(gt)
            return 'fail'

    # GT_GetLinear
    tuples = [(ogr.wkbPoint, ogr.wkbPoint),
              (ogr.wkbPoint25D, ogr.wkbPoint25D),
              (ogr.wkbPointM, ogr.wkbPointM),
              (ogr.wkbPointZM, ogr.wkbPointZM),
              (ogr.wkbCircularString, ogr.wkbLineString),
              (ogr.wkbCircularStringM, ogr.wkbLineStringM),
              (ogr.wkbCircularStringZ, ogr.wkbLineString25D),
              (ogr.wkbCircularStringZM, ogr.wkbLineStringZM),
              (ogr.wkbCompoundCurve, ogr.wkbLineString),
              (ogr.wkbCurvePolygon, ogr.wkbPolygon),
              (ogr.wkbLineString, ogr.wkbLineString),
              (ogr.wkbPolygon, ogr.wkbPolygon),
              (ogr.wkbMultiLineString, ogr.wkbMultiLineString),
              (ogr.wkbMultiPolygon, ogr.wkbMultiPolygon),
              (ogr.wkbMultiCurve, ogr.wkbMultiLineString),
              (ogr.wkbMultiSurface, ogr.wkbMultiPolygon)]
    for (gt, res) in tuples:
        if ogr.GT_GetLinear(gt) != res:
            gdaltest.post_reason('fail')
            print(gt)
            return 'fail'

    return 'success'

###############################################################################
# Limit cases


def ogr_geom_api_limit_tests():

    p = ogr.Geometry(ogr.wkbPoint)
    lyr = ogr.Geometry(ogr.wkbLineString)
    poly = ogr.Geometry(ogr.wkbPolygon)

    with gdaltest.error_handler():
        p.GetX(1)
        p.GetY(1)
        p.GetZ(1)

        lyr.GetX(1)
        lyr.GetY(1)
        lyr.GetZ(1)

        poly.GetX()
        poly.GetY()
        poly.GetZ()

        poly.GetPoints()

        p.GetPoint(1)
        lyr.GetPoint(1)
        poly.GetPoint(1)

        p.SetPoint(1, 0, 0)
        lyr.SetPoint(-1, 0, 0)
        poly.SetPoint(0, 0, 0)

        p.SetPoint_2D(1, 0, 0)
        lyr.SetPoint_2D(-1, 0, 0)
        poly.SetPoint_2D(0, 0, 0)

        poly.AddPoint(0, 0)

        poly.AddPoint_2D(0, 0)

        p.GetGeometryRef(1)

        p.AddGeometry(p)

        p.AddGeometryDirectly(p)

    return 'success'

###############################################################################
# Test Equals


def ogr_geom_equals():

    p_empty = ogr.Geometry(ogr.wkbPoint)
    p_0 = ogr.CreateGeometryFromWkt('POINT (0 0)')
    p_1 = ogr.CreateGeometryFromWkt('POINT (1 1)')
    if not p_empty.Equals(p_empty):
        gdaltest.post_reason('fail')
        return 'fail'
    if not p_0.Equals(p_0):
        gdaltest.post_reason('fail')
        return 'fail'
    if not p_0.Equals(p_0.Clone()):
        gdaltest.post_reason('fail')
        return 'fail'
    if p_empty.Equals(p_0):
        gdaltest.post_reason('fail')
        return 'fail'
    if p_0.Equals(p_empty):
        gdaltest.post_reason('fail')
        return 'fail'
    if p_0.Equals(p_1):
        gdaltest.post_reason('fail')
        return 'fail'

    l_empty = ogr.Geometry(ogr.wkbLineString)
    l_0_1 = ogr.CreateGeometryFromWkt('LINESTRING (0 0,1 1)')
    l_0_1_2 = ogr.CreateGeometryFromWkt('LINESTRING (0 0,1 1,2 2)')
    if not l_0_1.Equals(l_0_1):
        gdaltest.post_reason('fail')
        return 'fail'
    if not l_0_1.Equals(l_0_1.Clone()):
        gdaltest.post_reason('fail')
        return 'fail'
    if l_empty.Equals(l_0_1):
        gdaltest.post_reason('fail')
        return 'fail'
    if l_0_1.Equals(l_empty):
        gdaltest.post_reason('fail')
        return 'fail'
    if l_0_1.Equals(l_0_1_2):
        gdaltest.post_reason('fail')
        return 'fail'

    gc_empty = ogr.Geometry(ogr.wkbGeometryCollection)
    gc_p_0 = ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION (POINT (0 0))')
    gc_p_1 = ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION (POINT (1 1))')
    if not gc_empty.Equals(gc_empty):
        gdaltest.post_reason('fail')
        return 'fail'
    if not gc_p_0.Equals(gc_p_0):
        gdaltest.post_reason('fail')
        return 'fail'
    if not gc_p_0.Equals(gc_p_0.Clone()):
        gdaltest.post_reason('fail')
        return 'fail'
    if gc_empty.Equals(gc_p_0):
        gdaltest.post_reason('fail')
        return 'fail'
    if gc_p_0.Equals(gc_empty):
        gdaltest.post_reason('fail')
        return 'fail'
    if gc_p_0.Equals(gc_p_1):
        gdaltest.post_reason('fail')
        return 'fail'

    return 'success'

###############################################################################
# Test FlattenTo2D(), SetCoordinateDimension(2) and SetCoordinateDimension(3) with Measured geometries


def ogr_geom_measured_geometries_to_2D_or_3D():

    list_wkt = [['POINT M (1 2 3)', 'POINT (1 2)', 'POINT Z (1 2 0)'],
                ['POINT ZM (1 2 3 4)', 'POINT (1 2)', 'POINT Z (1 2 3)'],
                ['LINESTRING M (1 2 3)', 'LINESTRING (1 2)', 'LINESTRING Z (1 2 0)'],
                ['LINESTRING ZM (1 2 3 4)', 'LINESTRING (1 2)', 'LINESTRING Z (1 2 3)'],
                ['POLYGON M ((1 2 3))', 'POLYGON ((1 2))', 'POLYGON Z ((1 2 0))'],
                ['POLYGON ZM ((1 2 3 4))', 'POLYGON ((1 2))', 'POLYGON Z ((1 2 3))'],
                ['CIRCULARSTRING M (1 2 3,4 5 6,7 8 9)', 'CIRCULARSTRING (1 2,4 5,7 8)', 'CIRCULARSTRING Z (1 2 0,4 5 0,7 8 0)'],
                ['CIRCULARSTRING ZM (1 2 3 0,4 5 6 0,7 8 9 0)', 'CIRCULARSTRING (1 2,4 5,7 8)', 'CIRCULARSTRING Z (1 2 3,4 5 6,7 8 9)'],
                ['COMPOUNDCURVE M ((1 2 3,4 5 6))', 'COMPOUNDCURVE ((1 2,4 5))', 'COMPOUNDCURVE Z ((1 2 0,4 5 0))'],
                ['COMPOUNDCURVE ZM ((1 2 3 4,5 6 7 8))', 'COMPOUNDCURVE ((1 2,5 6))', 'COMPOUNDCURVE Z ((1 2 3,5 6 7))'],
                ['MULTIPOINT M ((1 2 3))', 'MULTIPOINT ((1 2))', 'MULTIPOINT Z ((1 2 0))'],
                ['MULTIPOINT ZM ((1 2 3 4))', 'MULTIPOINT ((1 2))', 'MULTIPOINT Z ((1 2 3))'],
                ['MULTILINESTRING M ((1 2 3))', 'MULTILINESTRING ((1 2))', 'MULTILINESTRING Z ((1 2 0))'],
                ['MULTILINESTRING ZM ((1 2 3 4))', 'MULTILINESTRING ((1 2))', 'MULTILINESTRING Z ((1 2 3))'],
                ['MULTICURVE M ((1 2 3))', 'MULTICURVE ((1 2))', 'MULTICURVE Z ((1 2 0))'],
                ['MULTICURVE ZM ((1 2 3 4))', 'MULTICURVE ((1 2))', 'MULTICURVE Z ((1 2 3))'],
                ['MULTIPOLYGON M (((1 2 3)))', 'MULTIPOLYGON (((1 2)))', 'MULTIPOLYGON Z (((1 2 0)))'],
                ['MULTIPOLYGON ZM (((1 2 3 4)))', 'MULTIPOLYGON (((1 2)))', 'MULTIPOLYGON Z (((1 2 3)))'],
                ['MULTISURFACE M (((1 2 3)))', 'MULTISURFACE (((1 2)))', 'MULTISURFACE Z (((1 2 0)))'],
                ['MULTISURFACE ZM (((1 2 3 4)))', 'MULTISURFACE (((1 2)))', 'MULTISURFACE Z (((1 2 3)))'],
                ['GEOMETRYCOLLECTION M (POINT M (1 2 3))', 'GEOMETRYCOLLECTION (POINT (1 2))', 'GEOMETRYCOLLECTION Z (POINT Z (1 2 0))'],
                ['GEOMETRYCOLLECTION ZM (POINT ZM (1 2 3 4))', 'GEOMETRYCOLLECTION (POINT (1 2))', 'GEOMETRYCOLLECTION Z (POINT Z (1 2 3))'],
                ['TRIANGLE M ((0 0 3,0 1 3,1 1 3,0 0 3))', 'TRIANGLE ((0 0,0 1,1 1,0 0))', 'TRIANGLE Z ((0 0 0,0 1 0,1 1 0,0 0 0))'],
                ['TRIANGLE ZM ((0 0 3 4,0 1 3 4,1 1 3 4,0 0 3 4))', 'TRIANGLE ((0 0,0 1,1 1,0 0))', 'TRIANGLE Z ((0 0 3,0 1 3,1 1 3,0 0 3))'],
                ['POLYHEDRALSURFACE M (((0 0 3,0 1 3,1 1 3,0 0 3)))', 'POLYHEDRALSURFACE (((0 0,0 1,1 1,0 0)))', 'POLYHEDRALSURFACE Z (((0 0 0,0 1 0,1 1 0,0 0 0)))'],
                ['POLYHEDRALSURFACE ZM (((0 0 3 4,0 1 3 4,1 1 3 4,0 0 3 4)))', 'POLYHEDRALSURFACE (((0 0,0 1,1 1,0 0)))', 'POLYHEDRALSURFACE Z (((0 0 3,0 1 3,1 1 3,0 0 3)))'],
                ['TIN M (((0 0 3,0 1 3,1 1 3,0 0 3)))', 'TIN (((0 0,0 1,1 1,0 0)))', 'TIN Z (((0 0 0,0 1 0,1 1 0,0 0 0)))'],
                ['TIN ZM (((0 0 3 4,0 1 3 4,1 1 3 4,0 0 3 4)))', 'TIN (((0 0,0 1,1 1,0 0)))', 'TIN Z (((0 0 3,0 1 3,1 1 3,0 0 3)))'],
                ]
    for (before, after_2D, after_3D) in list_wkt:

        geom = ogr.CreateGeometryFromWkt(before)
        wkb = geom.ExportToIsoWkb()
        geom2 = ogr.CreateGeometryFromWkb(wkb)
        if not geom.Equals(geom2):
            print(before)
            print(geom2.ExportToIsoWkt())
            return 'fail'

        geom = ogr.CreateGeometryFromWkt(before)
        geom.FlattenTo2D()
        if geom.ExportToIsoWkt() != after_2D:
            gdaltest.post_reason('fail')
            print(before)
            print(after_2D)
            print(geom.ExportToIsoWkt())
            return 'fail'

        geom = ogr.CreateGeometryFromWkt(before)
        geom.SetCoordinateDimension(2)
        if geom.ExportToIsoWkt() != after_2D:
            gdaltest.post_reason('fail')
            print(before)
            print(after_2D)
            print(geom.ExportToIsoWkt())
            return 'fail'

        geom = ogr.CreateGeometryFromWkt(before)
        geom.SetCoordinateDimension(3)
        if geom.ExportToIsoWkt() != after_3D:
            gdaltest.post_reason('fail')
            print(before)
            print(after_3D)
            print(geom.ExportToIsoWkt())
            return 'fail'

        # Test no-op
        geom = ogr.CreateGeometryFromWkt(before)
        geom.Set3D(geom.Is3D())
        geom.SetMeasured(geom.IsMeasured())
        if geom.ExportToIsoWkt() != before:
            gdaltest.post_reason('fail')
            print(before)
            print(geom.ExportToIsoWkt())
            return 'fail'

    if ogr.CreateGeometryFromWkt('POINT (1 2)').CoordinateDimension() != 2:
        gdaltest.post_reason('fail')
        return 'fail'

    if ogr.CreateGeometryFromWkt('POINT M (1 2 3)').CoordinateDimension() != 3:
        gdaltest.post_reason('fail')
        return 'fail'

    if ogr.CreateGeometryFromWkt('POINT Z (1 2 3)').CoordinateDimension() != 3:
        gdaltest.post_reason('fail')
        return 'fail'

    if ogr.CreateGeometryFromWkt('POINT ZM (1 2 3 4)').CoordinateDimension() != 4:
        gdaltest.post_reason('fail')
        return 'fail'

    # Unrelated test. Test old-style unqualified non-bracketted ZM import
    g = ogr.CreateGeometryFromWkt('MULTIPOINT (1 2 3 4)')
    if g.ExportToIsoWkt() != 'MULTIPOINT ZM ((1 2 3 4))':
        gdaltest.post_reason('fail')
        print(g.ExportToIsoWkt())
        return 'fail'

    return 'success'

###############################################################################
# Test PostGIS EWKT with XYM


def ogr_geom_postgis_ewkt_xym():

    list_wkt = [['POINTM(1 2 3)', 'POINT M (1 2 3)'],
                ['GEOMETRYCOLLECTIONM(POINTM(1 2 3))', 'GEOMETRYCOLLECTION M (POINT M (1 2 3))'],
                ]
    for (before, after) in list_wkt:
        geom = ogr.CreateGeometryFromWkt(before)
        if geom.ExportToIsoWkt() != after:
            gdaltest.post_reason('fail')
            print(before)
            print(after)
            print(geom.ExportToIsoWkt())
            return 'fail'

    return 'success'

###############################################################################
# Test ogr.wkbCurve / ogr.wkbSurface


def ogr_geom_curve_surface():

    tests = [[ogr.wkbCurve, "Curve"],
             [ogr.wkbCurveZ, "3D Curve"],
             [ogr.wkbCurveM, "Measured Curve"],
             [ogr.wkbCurveZM, "3D Measured Curve"],
             [ogr.wkbSurface, "Surface"],
             [ogr.wkbSurfaceZ, "3D Surface"],
             [ogr.wkbSurfaceM, "Measured Surface"],
             [ogr.wkbSurfaceZM, "3D Measured Surface"]]

    for (wkb_type, name) in tests:
        if ogr.GeometryTypeToName(wkb_type) != name:
            gdaltest.post_reason('fail')
            print(wkb_type)
            print(name)
            print(ogr.GeometryTypeToName(wkb_type))
            return 'fail'

    return 'success'

###############################################################################
# Test importing corrupted WKB


def ogr_geom_import_corrupted_wkb():

    list_wkt = ['POINT ZM (1 2 3 4)'
                'LINESTRING ZM (1 2 3 4)'
                'POLYGON ZM ((1 2 3 4))'
                'CIRCULARSTRING ZM (1 2 3 0,4 5 6 0,7 8 9 0)',
                'COMPOUNDCURVE ZM ((1 2 3 4,5 6 7 8))',
                'MULTIPOINT ZM ((1 2 3 4))',
                'MULTILINESTRING ZM ((1 2 3 4))',
                'MULTICURVE ZM ((1 2 3 4))',
                'MULTIPOLYGON ZM (((1 2 3 4)))',
                'MULTISURFACE ZM (((1 2 3 4)))',
                'GEOMETRYCOLLECTION ZM (POINT ZM (1 2 3 4))',
                'TRIANGLE ZM ((0 0 3 4,0 1 3 4,1 1 3 4,0 0 3 4))',
                'POLYHEDRALSURFACE ZM (((0 0 3 4,0 1 3 4,1 1 3 4,0 0 3 4)),((0 0 3 4,0 1 3 4,1 1 3 4,0 0 3 4)))',
                'TIN ZM (((0 0 3 4,0 1 3 4,1 1 3 4,0 0 3 4)),((0 0 3 4,0 1 3 4,1 1 3 4,0 0 3 4)))',
                ]

    for wkt in list_wkt:
        g = ogr.CreateGeometryFromWkt(wkt)
        wkb = bytearray(g.ExportToWkb())

        # Test altering the WKB
        for i in range(len(wkb)):
            for method in range(4 + 4 + 4 + 1):
                init_val = wkb[i]
                if method < 4:
                    wkb[i] = method
                elif method < 8:
                    wkb[i] = 255 - (method - 4)
                elif method < 12:
                    wkb[i] = 127 + 2 - (method - 8)
                else:
                    wkb[i] = 255 - wkb[i]
                with gdaltest.error_handler():
                    if sys.version_info >= (3, 0, 0):
                        g = ogr.CreateGeometryFromWkb(bytes(wkb))
                    else:
                        g = ogr.CreateGeometryFromWkb(str(wkb))
                if g:
                    g2 = ogr.CreateGeometryFromWkb(g.ExportToIsoWkb())
                    if not g.Equals(g2):
                        gdaltest.post_reason('fail')
                        print(wkt, i, method)
                        return 'fail'
                wkb[i] = init_val

        # Test truncation of the WKB
        for i in range(len(wkb)):
            with gdaltest.error_handler():
                if sys.version_info >= (3, 0, 0):
                    g = ogr.CreateGeometryFromWkb(bytes(wkb[0:i]))
                else:
                    g = ogr.CreateGeometryFromWkb(str(wkb[0:i]))
            if g is not None:
                gdaltest.post_reason('fail')
                print(wkt, i)
                return 'fail'

    return 'success'

###############################################################################
# Test conversions from/into triangle, TIN, PS


def ogr_geom_triangle_ps_tin_conversion():

    wkts = ["TRIANGLE ((0 0,0 1,1 1,0 0))",
            "POLYGON ((0 0,0 1,1 1,0 0))",
            "CURVEPOLYGON ((0 0,0 1,1 1,0 0))",
            "MULTIPOLYGON (((0 0,0 1,1 1,0 0)))",
            "MULTISURFACE (((0 0,0 1,1 1,0 0)))",
            "TIN (((0 0,0 1,1 1,0 0)))",
            "POLYHEDRALSURFACE (((0 0,0 1,1 1,0 0)))"]

    for wkt in wkts:
        for wkt_target in wkts:
            # print(wkt, wkt_target)
            g = ogr.CreateGeometryFromWkt(wkt)
            g2 = ogr.CreateGeometryFromWkt(wkt_target)
            got_wkt = ogr.ForceTo(g, g2.GetGeometryType()).ExportToWkt()
            if not (g.GetGeometryType() in [ogr.wkbTriangle, ogr.wkbTIN, ogr.wkbPolyhedralSurface] or
                    g2.GetGeometryType() in [ogr.wkbTriangle, ogr.wkbTIN, ogr.wkbPolyhedralSurface]):
                continue
            wkt_expected = wkt_target
            if (g.GetGeometryType() == ogr.wkbTIN or g.GetGeometryType() == ogr.wkbPolyhedralSurface) and g2.GetGeometryType() == ogr.wkbCurvePolygon:
                wkt_expected = wkt
            if got_wkt != wkt_expected:
                gdaltest.post_reason('fail')
                print(wkt, wkt_target, got_wkt, wkt_expected)
                return 'fail'

    g = ogr.ForceTo(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 1,1 1,1 0,0 0))'), ogr.wkbTriangle)
    if g.GetGeometryType() != ogr.wkbPolygon:
        gdaltest.post_reason('fail')
        print(g.ExportToWkt())
        return 'fail'

    g = ogr.ForceTo(ogr.CreateGeometryFromWkt('POLYHEDRALSURFACE (((0 0,0 1,1 1,1 0,0 0)))'), ogr.wkbTIN)
    if g.GetGeometryType() != ogr.wkbPolyhedralSurface:
        gdaltest.post_reason('fail')
        print(g.ExportToWkt())
        return 'fail'

    g = ogr.ForceTo(ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION (POLYHEDRALSURFACE (((0 0,0 1,1 1,1 0,0 0))))'), ogr.wkbMultiPolygon)
    if g.ExportToWkt() != 'MULTIPOLYGON (((0 0,0 1,1 1,1 0,0 0)))':
        gdaltest.post_reason('fail')
        print(g.ExportToWkt())
        return 'fail'

    g = ogr.ForceTo(ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION (TRIANGLE ((0 0,0 1,1 1,0 0)))'), ogr.wkbMultiPolygon)
    if g.ExportToWkt() != 'MULTIPOLYGON (((0 0,0 1,1 1,0 0)))':
        gdaltest.post_reason('fail')
        print(g.ExportToWkt())
        return 'fail'

    g = ogr.ForceTo(ogr.CreateGeometryFromWkt('MULTIPOLYGON (((0 0,0 1,1 1,0 0)))'), ogr.wkbGeometryCollection)
    if g.ExportToWkt() != 'GEOMETRYCOLLECTION (POLYGON ((0 0,0 1,1 1,0 0)))':
        gdaltest.post_reason('fail')
        print(g.ExportToWkt())
        return 'fail'

    g = ogr.ForceTo(ogr.CreateGeometryFromWkt('TRIANGLE ((0 0,0 1,1 1,0 0))'), ogr.wkbGeometryCollection)
    if g.ExportToWkt() != 'GEOMETRYCOLLECTION (TRIANGLE ((0 0,0 1,1 1,0 0)))':
        gdaltest.post_reason('fail')
        print(g.ExportToWkt())
        return 'fail'

    g = ogr.ForceTo(ogr.CreateGeometryFromWkt('TIN (((0 0,0 1,1 1,0 0)))'), ogr.wkbGeometryCollection)
    if g.ExportToWkt() != 'GEOMETRYCOLLECTION (POLYGON ((0 0,0 1,1 1,0 0)))':
        gdaltest.post_reason('fail')
        print(g.ExportToWkt())
        return 'fail'

    g = ogr.ForceTo(ogr.CreateGeometryFromWkt('POLYHEDRALSURFACE (((0 0,0 1,1 1,0 0)))'), ogr.wkbGeometryCollection)
    if g.ExportToWkt() != 'GEOMETRYCOLLECTION (POLYGON ((0 0,0 1,1 1,0 0)))':
        gdaltest.post_reason('fail')
        print(g.ExportToWkt())
        return 'fail'

    return 'success'

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


def ogr_geom_multipoint_envelope_bug():

    g = ogr.CreateGeometryFromWkt('MULTIPOINT(0 0,1 1)')
    minx, maxx, miny, maxy = g.GetEnvelope()
    if (minx, maxx, miny, maxy) != (0, 1, 0, 1):
        gdaltest.post_reason('fail')
        print(minx, maxx, miny, maxy)
        return 'fail'

    g = ogr.CreateGeometryFromWkt('MULTIPOINT(0 0 0,1 1 1)')
    minx, maxx, miny, maxy, minz, maxz = g.GetEnvelope3D()
    if (minx, maxx, miny, maxy, minz, maxz) != (0, 1, 0, 1, 0, 1):
        gdaltest.post_reason('fail')
        print(minx, maxx, miny, maxy, minz, maxz)
        return 'fail'

    return 'success'

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


def ogr_geom_polygon_empty_ring():

    g = ogr.Geometry(ogr.wkbPolygon)
    g2 = ogr.Geometry(ogr.wkbLinearRing)
    g.AddGeometryDirectly(g2)
    if not g.IsEmpty():
        return 'fail'

    return 'success'

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


def ogr_geom_polygon_intersects_point():

    if not ogrtest.have_geos():
        return 'skip'

    poly = ogr.CreateGeometryFromWkt('POLYGON((0 0,5 5,10 0,0 0))')
    point = ogr.Geometry(ogr.wkbPoint)
    point.AddPoint(10, 0)
    if poly.Intersects(point) != 1:
        gdaltest.post_reason('fail')
        return 'fail'
    if poly.Contains(point) != 0:
        gdaltest.post_reason('fail')
        return 'fail'

    return 'success'

###############################################################################
# Test fix for #7128


def ogr_geom_geometrycollection():

    wkt_list = ['GEOMETRYCOLLECTION (POINT EMPTY)',
                'GEOMETRYCOLLECTION (LINESTRING EMPTY)',
                'GEOMETRYCOLLECTION (POLYGON EMPTY)',
                'GEOMETRYCOLLECTION (MULTIPOINT EMPTY)',
                'GEOMETRYCOLLECTION (MULTILINESTRING EMPTY)',
                'GEOMETRYCOLLECTION (MULTIPOLYGON EMPTY)',
                'GEOMETRYCOLLECTION (GEOMETRYCOLLECTION EMPTY)',
                'GEOMETRYCOLLECTION (CIRCULARSTRING EMPTY)',
                'GEOMETRYCOLLECTION (COMPOUNDCURVE EMPTY)',
                'GEOMETRYCOLLECTION (CURVEPOLYGON EMPTY)',
                'GEOMETRYCOLLECTION (MULTICURVE EMPTY)',
                'GEOMETRYCOLLECTION (MULTISURFACE EMPTY)',
                'GEOMETRYCOLLECTION (TRIANGLE EMPTY)',
                'GEOMETRYCOLLECTION (POLYHEDRALSURFACE EMPTY)',
                'GEOMETRYCOLLECTION (TIN EMPTY)']
    for wkt in wkt_list:
        g = ogr.CreateGeometryFromWkt(wkt)
        if g.ExportToWkt() != wkt:
            print(g.ExportToWkt(), wkt)
            return 'fail'

    return 'success'

###############################################################################
# Test fix for #7126


def ogr_geom_assignspatialref():

    g = ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION(POLYGON((0 0,0 1,1 1,0 0)),COMPOUNDCURVE(CIRCULARSTRING(0 0,1 1,2 0)),POLYHEDRALSURFACE(((0 0,0 1,1 1,0 0))))')
    sr = osr.SpatialReference()
    sr.ImportFromEPSG(4326)
    g.AssignSpatialReference(sr)
    if g.GetGeometryRef(0).GetSpatialReference().ExportToWkt() != sr.ExportToWkt():
        return 'fail'
    if g.GetGeometryRef(0).GetGeometryRef(0).GetSpatialReference().ExportToWkt() != sr.ExportToWkt():
        return 'fail'
    if g.GetGeometryRef(1).GetSpatialReference().ExportToWkt() != sr.ExportToWkt():
        return 'fail'
    if g.GetGeometryRef(1).GetGeometryRef(0).GetSpatialReference().ExportToWkt() != sr.ExportToWkt():
        return 'fail'
    if g.GetGeometryRef(2).GetSpatialReference().ExportToWkt() != sr.ExportToWkt():
        return 'fail'
    if g.GetGeometryRef(2).GetGeometryRef(0).GetSpatialReference().ExportToWkt() != sr.ExportToWkt():
        return 'fail'

    return 'success'

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


def ogr_geom_swapxy():

    g = ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(1 2,2 3),POLYGON((0 0,0 1,1 1,0 0)),COMPOUNDCURVE(CIRCULARSTRING(0 0,1 1,2 0)),POLYHEDRALSURFACE(((0 0,0 1,1 1,0 0))))')
    g.SwapXY()
    if g.ExportToWkt() != 'GEOMETRYCOLLECTION (POINT (2 1),LINESTRING (2 1,3 2),POLYGON ((0 0,1 0,1 1,0 0)),COMPOUNDCURVE (CIRCULARSTRING (0 0,1 1,0 2)),POLYHEDRALSURFACE (((0 0,1 0,1 1,0 0))))':
        print(g)
        return 'fail'

    return 'success'

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


def ogr_geom_remove_geometry():

    # With GEOMETRYCOLLECTION
    g = ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION (POINT (1 2),LINESTRING (1 2,2 3),POINT (3 4))')
    if g.RemoveGeometry(3) == 0 or g.RemoveGeometry(-2) == 0:
        gdaltest.post_reason('fail')
        return 'fail'

    if g.RemoveGeometry(1) != 0:
        gdaltest.post_reason('fail')
        return 'fail'
    if g.ExportToWkt() != 'GEOMETRYCOLLECTION (POINT (1 2),POINT (3 4))':
        gdaltest.post_reason('fail')
        print(g)
        return 'fail'

    if g.RemoveGeometry(1) != 0:
        gdaltest.post_reason('fail')
        return 'fail'
    if g.ExportToWkt() != 'GEOMETRYCOLLECTION (POINT (1 2))':
        gdaltest.post_reason('fail')
        print(g)
        return 'fail'

    if g.RemoveGeometry(0) != 0:
        gdaltest.post_reason('fail')
        return 'fail'
    if g.ExportToWkt() != 'GEOMETRYCOLLECTION EMPTY':
        gdaltest.post_reason('fail')
        print(g)
        return 'fail'

    g = ogr.CreateGeometryFromWkt('GEOMETRYCOLLECTION (POINT (1 2),LINESTRING (1 2,2 3),POINT (3 4))')
    if g.RemoveGeometry(-1) != 0:
        gdaltest.post_reason('fail')
        return 'fail'
    if g.ExportToWkt() != 'GEOMETRYCOLLECTION EMPTY':
        gdaltest.post_reason('fail')
        print(g)
        return 'fail'

    # With POLYHEDRALSURFACE/TIN
    g = ogr.CreateGeometryFromWkt('TIN (((0 0,0 1,1 1,0 0)),((0 0,1 0,1 1,0 0)))')
    if g.RemoveGeometry(2) == 0 or g.RemoveGeometry(-2) == 0:
        gdaltest.post_reason('fail')
        return 'fail'

    if g.RemoveGeometry(1) != 0:
        gdaltest.post_reason('fail')
        return 'fail'
    if g.ExportToWkt() != 'TIN (((0 0,0 1,1 1,0 0)))':
        gdaltest.post_reason('fail')
        print(g)
        return 'fail'

    if g.RemoveGeometry(0) != 0:
        gdaltest.post_reason('fail')
        return 'fail'
    if g.ExportToWkt() != 'TIN EMPTY':
        gdaltest.post_reason('fail')
        print(g)
        return 'fail'

    g = ogr.CreateGeometryFromWkt('TIN (((0 0,0 1,1 1,0 0)),((0 0,1 0,1 1,0 0)))')
    if g.RemoveGeometry(-1) != 0:
        gdaltest.post_reason('fail')
        return 'fail'
    if g.ExportToWkt() != 'TIN EMPTY':
        gdaltest.post_reason('fail')
        print(g)
        return 'fail'

    # With POLYGON
    g = ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 10,10 10,10 0,0 0),(1 1,1 9,9 9,1 1))')
    if g.RemoveGeometry(2) == 0 or g.RemoveGeometry(-2) == 0:
        gdaltest.post_reason('fail')
        return 'fail'

    if g.RemoveGeometry(1) != 0:
        gdaltest.post_reason('fail')
        return 'fail'
    if g.ExportToWkt() != 'POLYGON ((0 0,0 10,10 10,10 0,0 0))':
        gdaltest.post_reason('fail')
        print(g)
        return 'fail'

    if g.RemoveGeometry(0) != 0:
        gdaltest.post_reason('fail')
        return 'fail'
    if g.ExportToWkt() != 'POLYGON EMPTY':
        gdaltest.post_reason('fail')
        print(g)
        return 'fail'

    g = ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 10,10 10,10 0,0 0),(1 1,1 9,9 9,1 1))')
    if g.RemoveGeometry(-1) != 0:
        gdaltest.post_reason('fail')
        return 'fail'
    if g.ExportToWkt() != 'POLYGON EMPTY':
        gdaltest.post_reason('fail')
        print(g)
        return 'fail'

    # Unsupported type
    g = ogr.CreateGeometryFromWkt('POINT (0 0)')
    if g.RemoveGeometry(0) == 0:
        gdaltest.post_reason('fail')
        return 'fail'

    return 'success'

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


def ogr_geom_sfcgal():

    if not ogrtest.have_sfcgal():
        return 'skip'

    g1 = ogr.CreateGeometryFromWkt('TIN EMPTY')

    g2_poly = ogr.CreateGeometryFromWkt('POLYGON((0 0,0 1,1 1,0 0))')
    g2 = g2_poly.GetGeometryRef(0)
    g1.Distance(g2)

    g2 = ogr.CreateGeometryFromWkt('CIRCULARSTRING EMPTY')
    g1.Distance(g2)

    g2 = ogr.CreateGeometryFromWkt('CURVEPOLYGON EMPTY')
    g1.Distance(g2)

    return 'success'

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


def ogr_geom_cannot_add_triangle_to_multisurface():

    g = ogr.Geometry(ogr.wkbMultiSurface)
    if g.AddGeometry(ogr.Geometry(ogr.wkbTriangle)) == 0:
        return 'fail'
    return 'success'

###############################################################################
# cleanup


def ogr_geom_cleanup():
    return 'success'


gdaltest_list = [
    ogr_geom_area,
    ogr_geom_polyhedral_surface,
    ogr_geom_tin,
    ogr_geom_area_triangle,
    ogr_geom_area_linearring,
    ogr_geom_area_linearring_big_offset,
    ogr_geom_area_geometrycollection,
    ogr_geom_is_empty,
    ogr_geom_is_empty_triangle,
    ogr_geom_pickle,
    ogr_geom_boundary_point,
    ogr_geom_boundary_multipoint,
    ogr_geom_boundary_linestring,
    ogr_geom_boundary_polygon,
    ogr_geom_build_from_edges_1,
    ogr_geom_build_from_edges_2,
    ogr_geom_build_from_edges_3,
    ogr_geom_build_from_edges_4,
    ogr_geom_area_empty_linearring,
    ogr_geom_transform_to,
    ogr_geom_transform,
    ogr_geom_closerings,
    ogr_geom_segmentize,
    ogr_geom_value,
    ogr_geom_flattenTo2D,
    ogr_geom_flattenTo2D_triangle,
    ogr_geom_linestring_limits,
    ogr_geom_coord_round,
    ogr_geom_coord_round_2,
    ogr_geom_area_point,
    ogr_geom_length_point,
    ogr_geom_length_multilinestring,
    ogr_geom_length_geometrycollection,
    ogr_geom_empty_triangle,
    ogr_geom_triangle,
    ogr_geom_triangle_invalid_wkt,
    ogr_geom_triangle_sfcgal,
    ogr_geom_empty,
    ogr_geom_getpoints,
    ogr_geom_mixed_coordinate_dimension,
    ogr_geom_getenvelope3d,
    ogr_geom_z_empty,
    ogr_geom_getlineargeometry,
    ogr_geom_getdimension,
    ogr_geom_circularstring,
    ogr_geom_compoundcurve,
    ogr_geom_curvepolygon,
    ogr_geom_multicurve,
    ogr_geom_multisurface,
    ogr_geom_getcurvegeometry,
    ogr_geom_gt_functions,
    ogr_geom_api_limit_tests,
    ogr_geom_equals,
    ogr_geom_measured_geometries_to_2D_or_3D,
    ogr_geom_postgis_ewkt_xym,
    ogr_geom_curve_surface,
    ogr_geom_import_corrupted_wkb,
    ogr_geom_triangle_ps_tin_conversion,
    ogr_geom_multipoint_envelope_bug,
    ogr_geom_polygon_empty_ring,
    ogr_geom_polygon_intersects_point,
    ogr_geom_geometrycollection,
    ogr_geom_assignspatialref,
    ogr_geom_swapxy,
    ogr_geom_remove_geometry,
    ogr_geom_sfcgal,
    ogr_geom_cannot_add_triangle_to_multisurface,
    ogr_geom_cleanup]

# gdaltest_list = [ ogr_geom_triangle_ps_tin_conversion ]

if __name__ == '__main__':

    gdaltest.setup_run('ogr_geom')

    gdaltest.run_tests(gdaltest_list)

    gdaltest.summarize()
