4365 строки
140 KiB
Python
Исполняемый файл
4365 строки
140 KiB
Python
Исполняемый файл
#!/usr/bin/env pytest
|
|
# -*- coding: utf-8 -*-
|
|
###############################################################################
|
|
# $Id$
|
|
#
|
|
# Project: GDAL/OGR Test Suite
|
|
# Purpose: GeoJSON driver test suite.
|
|
# Author: Mateusz Loskot <mateusz@loskot.net>
|
|
#
|
|
###############################################################################
|
|
# Copyright (c) 2007, Mateusz Loskot <mateusz@loskot.net>
|
|
# Copyright (c) 2009-2014, Even Rouault <even dot rouault at spatialys.com>
|
|
# Copyright (c) 2013, Kyle Shannon <kyle at pobox dot com>
|
|
#
|
|
# This library is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU Library General Public
|
|
# License as published by the Free Software Foundation; either
|
|
# version 2 of the License, or (at your option) any later version.
|
|
#
|
|
# This library is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Library General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Library General Public
|
|
# License along with this library; if not, write to the
|
|
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
# Boston, MA 02111-1307, USA.
|
|
###############################################################################
|
|
|
|
import json
|
|
import math
|
|
import os
|
|
import struct
|
|
|
|
import gdaltest
|
|
import ogrtest
|
|
import pytest
|
|
|
|
from osgeo import gdal, ogr, osr
|
|
|
|
pytestmark = pytest.mark.require_driver("GeoJSON")
|
|
|
|
###############################################################################
|
|
# Test utilities
|
|
|
|
|
|
def validate_layer(lyr, name, features, typ, fields, box):
|
|
|
|
if name is not None and name != lyr.GetName():
|
|
print("Wrong layer name")
|
|
return False
|
|
|
|
if features != lyr.GetFeatureCount():
|
|
print("Wrong number of features")
|
|
return False
|
|
|
|
lyrDefn = lyr.GetLayerDefn()
|
|
if lyrDefn is None:
|
|
print("Layer definition is none")
|
|
return False
|
|
|
|
if typ != lyrDefn.GetGeomType():
|
|
print("Wrong geometry type")
|
|
print(lyrDefn.GetGeomType())
|
|
return False
|
|
|
|
if fields != lyrDefn.GetFieldCount():
|
|
print("Wrong number of fields")
|
|
return False
|
|
|
|
extent = lyr.GetExtent()
|
|
|
|
minx = abs(extent[0] - box[0])
|
|
maxx = abs(extent[1] - box[1])
|
|
miny = abs(extent[2] - box[2])
|
|
maxy = abs(extent[3] - box[3])
|
|
|
|
if max(minx, maxx, miny, maxy) > 0.0001:
|
|
print("Wrong spatial extent of layer")
|
|
print(extent)
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def verify_geojson_copy(fname, fids, names):
|
|
|
|
if gdaltest.gjpoint_feat is None:
|
|
print("Missing features collection")
|
|
return False
|
|
|
|
ds = ogr.Open(fname)
|
|
if ds is None:
|
|
print("Can not open '" + fname + "'")
|
|
return False
|
|
|
|
lyr = ds.GetLayer(0)
|
|
if lyr is None:
|
|
print("Missing layer")
|
|
return False
|
|
|
|
######################################################
|
|
# Test attributes
|
|
ret = ogrtest.check_features_against_list(lyr, "FID", fids)
|
|
if ret != 1:
|
|
print("Wrong values in 'FID' field")
|
|
return False
|
|
|
|
lyr.ResetReading()
|
|
ret = ogrtest.check_features_against_list(lyr, "NAME", names)
|
|
if ret != 1:
|
|
print("Wrong values in 'NAME' field")
|
|
return False
|
|
|
|
######################################################
|
|
# Test geometries
|
|
lyr.ResetReading()
|
|
for i in range(len(gdaltest.gjpoint_feat)):
|
|
|
|
orig_feat = gdaltest.gjpoint_feat[i]
|
|
feat = lyr.GetNextFeature()
|
|
|
|
if feat is None:
|
|
print("Failed trying to read feature")
|
|
return False
|
|
|
|
if (
|
|
ogrtest.check_feature_geometry(
|
|
feat, orig_feat.GetGeometryRef(), max_error=0.001
|
|
)
|
|
!= 0
|
|
):
|
|
print("Geometry test failed")
|
|
gdaltest.gjpoint_feat = None
|
|
return False
|
|
|
|
gdaltest.gjpoint_feat = None
|
|
|
|
lyr = None
|
|
|
|
return True
|
|
|
|
|
|
def copy_shape_to_geojson(gjname, compress=None):
|
|
|
|
if compress is not None:
|
|
if compress[0:5] == "/vsig":
|
|
dst_name = os.path.join("/vsigzip/", "tmp", gjname + ".geojson" + ".gz")
|
|
elif compress[0:4] == "/vsiz":
|
|
dst_name = os.path.join("/vsizip/", "tmp", gjname + ".geojson" + ".zip")
|
|
elif compress == "/vsistdout/":
|
|
dst_name = compress
|
|
else:
|
|
return False, None
|
|
else:
|
|
dst_name = os.path.join("tmp", gjname + ".geojson")
|
|
|
|
ds = gdal.GetDriverByName("GeoJSON").Create(dst_name, 0, 0, 0, gdal.GDT_Unknown)
|
|
if ds is None:
|
|
return False, dst_name
|
|
|
|
######################################################
|
|
# Create layer
|
|
lyr = ds.CreateLayer(gjname)
|
|
if lyr is None:
|
|
return False, dst_name
|
|
|
|
######################################################
|
|
# Setup schema (all test shapefiles use common schema)
|
|
ogrtest.quick_create_layer_def(lyr, [("FID", ogr.OFTReal), ("NAME", ogr.OFTString)])
|
|
|
|
######################################################
|
|
# Copy in gjpoint.shp
|
|
|
|
dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn())
|
|
|
|
src_name = os.path.join("data", "shp", gjname + ".shp")
|
|
shp_ds = ogr.Open(src_name)
|
|
shp_lyr = shp_ds.GetLayer(0)
|
|
|
|
feat = shp_lyr.GetNextFeature()
|
|
gdaltest.gjpoint_feat = []
|
|
|
|
while feat is not None:
|
|
|
|
gdaltest.gjpoint_feat.append(feat)
|
|
|
|
dst_feat.SetFrom(feat)
|
|
lyr.CreateFeature(dst_feat)
|
|
|
|
feat = shp_lyr.GetNextFeature()
|
|
|
|
shp_lyr = None
|
|
lyr = None
|
|
|
|
assert ds.FlushCache() == gdal.CE_None
|
|
ds = None
|
|
|
|
return True, dst_name
|
|
|
|
|
|
###############################################################################
|
|
# Test file-based DS with standalone "Point" feature object.
|
|
|
|
|
|
def test_ogr_geojson_2():
|
|
|
|
ds = ogr.Open("data/geojson/point.geojson")
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
assert ds.GetLayerCount() == 1, "Wrong number of layers"
|
|
|
|
lyr = ds.GetLayerByName("point")
|
|
assert lyr is not None, "Missing layer called point"
|
|
|
|
extent = (100.0, 100.0, 0.0, 0.0)
|
|
|
|
rc = validate_layer(lyr, "point", 1, ogr.wkbPoint, 0, extent)
|
|
assert rc
|
|
|
|
lyr = None
|
|
|
|
|
|
###############################################################################
|
|
# Test file-based DS with standalone "LineString" feature object.
|
|
|
|
|
|
def test_ogr_geojson_3():
|
|
|
|
ds = ogr.Open("data/geojson/linestring.geojson")
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
assert ds.GetLayerCount() == 1, "Wrong number of layers"
|
|
|
|
lyr = ds.GetLayerByName("linestring")
|
|
assert lyr is not None, "Missing layer called linestring"
|
|
|
|
extent = (100.0, 101.0, 0.0, 1.0)
|
|
|
|
rc = validate_layer(lyr, "linestring", 1, ogr.wkbLineString, 0, extent)
|
|
assert rc
|
|
|
|
lyr = None
|
|
|
|
|
|
##############################################################################
|
|
# Test file-based DS with standalone "Polygon" feature object.
|
|
|
|
|
|
def test_ogr_geojson_4():
|
|
|
|
ds = ogr.Open("data/geojson/polygon.geojson")
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
assert ds.GetLayerCount() == 1, "Wrong number of layers"
|
|
|
|
lyr = ds.GetLayerByName("polygon")
|
|
assert lyr is not None, "Missing layer called polygon"
|
|
|
|
extent = (100.0, 101.0, 0.0, 1.0)
|
|
|
|
rc = validate_layer(lyr, "polygon", 1, ogr.wkbPolygon, 0, extent)
|
|
assert rc
|
|
|
|
lyr = None
|
|
|
|
|
|
##############################################################################
|
|
# Test file-based DS with standalone "GeometryCollection" feature object.
|
|
|
|
|
|
def test_ogr_geojson_5():
|
|
|
|
ds = ogr.Open("data/geojson/geometrycollection.geojson")
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
assert ds.GetLayerCount() == 1, "Wrong number of layers"
|
|
|
|
lyr = ds.GetLayerByName("geometrycollection")
|
|
assert lyr is not None, "Missing layer called geometrycollection"
|
|
|
|
extent = (100.0, 102.0, 0.0, 1.0)
|
|
|
|
rc = validate_layer(
|
|
lyr, "geometrycollection", 1, ogr.wkbGeometryCollection, 0, extent
|
|
)
|
|
assert rc
|
|
|
|
lyr = None
|
|
|
|
|
|
##############################################################################
|
|
# Test file-based DS with standalone "MultiPoint" feature object.
|
|
|
|
|
|
def test_ogr_geojson_6():
|
|
|
|
ds = ogr.Open("data/geojson/multipoint.geojson")
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
assert ds.GetLayerCount() == 1, "Wrong number of layers"
|
|
|
|
lyr = ds.GetLayerByName("multipoint")
|
|
assert lyr is not None, "Missing layer called multipoint"
|
|
|
|
extent = (100.0, 101.0, 0.0, 1.0)
|
|
|
|
rc = validate_layer(lyr, "multipoint", 1, ogr.wkbMultiPoint, 0, extent)
|
|
assert rc
|
|
|
|
lyr = None
|
|
|
|
|
|
##############################################################################
|
|
# Test file-based DS with standalone "MultiLineString" feature object.
|
|
|
|
|
|
def test_ogr_geojson_7():
|
|
|
|
ds = ogr.Open("data/geojson/multilinestring.geojson")
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
assert ds.GetLayerCount() == 1, "Wrong number of layers"
|
|
|
|
lyr = ds.GetLayerByName("multilinestring")
|
|
assert lyr is not None, "Missing layer called multilinestring"
|
|
|
|
extent = (100.0, 103.0, 0.0, 3.0)
|
|
|
|
rc = validate_layer(lyr, "multilinestring", 1, ogr.wkbMultiLineString, 0, extent)
|
|
assert rc
|
|
|
|
lyr = None
|
|
|
|
|
|
##############################################################################
|
|
# Test file-based DS with standalone "MultiPolygon" feature object.
|
|
|
|
|
|
def test_ogr_geojson_8():
|
|
|
|
ds = ogr.Open("data/geojson/multipolygon.geojson")
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
assert ds.GetLayerCount() == 1, "Wrong number of layers"
|
|
|
|
lyr = ds.GetLayerByName("multipolygon")
|
|
assert lyr is not None, "Missing layer called multipolygon"
|
|
|
|
extent = (100.0, 103.0, 0.0, 3.0)
|
|
|
|
rc = validate_layer(lyr, "multipolygon", 1, ogr.wkbMultiPolygon, 0, extent)
|
|
assert rc
|
|
|
|
lyr = None
|
|
|
|
|
|
##############################################################################
|
|
# Test translation of data/gjpoint.shp to GeoJSON file
|
|
|
|
|
|
def test_ogr_geojson_9():
|
|
|
|
tests = [
|
|
["gjpoint", [1], ["Point 1"]],
|
|
["gjline", [1], ["Line 1"]],
|
|
["gjpoly", [1], ["Polygon 1"]],
|
|
["gjmultipoint", [1], ["MultiPoint 1"]],
|
|
["gjmultiline", [2], ["MultiLine 1"]],
|
|
["gjmultipoly", [2], ["MultiPoly 1"]],
|
|
]
|
|
|
|
for test in tests:
|
|
|
|
rc, dstname = copy_shape_to_geojson(test[0])
|
|
try:
|
|
assert rc, "Failed making copy of " + test[0] + ".shp"
|
|
|
|
rc = verify_geojson_copy(dstname, test[1], test[2])
|
|
assert rc, "Verification of copy of " + test[0] + ".shp failed"
|
|
finally:
|
|
if dstname:
|
|
gdal.Unlink(dstname)
|
|
|
|
|
|
##############################################################################
|
|
# Test translation of data/gjpoint.shp to GZip compressed GeoJSON file
|
|
|
|
|
|
def test_ogr_geojson_10():
|
|
|
|
tests = [
|
|
["gjpoint", [1], ["Point 1"]],
|
|
["gjline", [1], ["Line 1"]],
|
|
["gjpoly", [1], ["Polygon 1"]],
|
|
["gjmultipoint", [1], ["MultiPoint 1"]],
|
|
["gjmultiline", [2], ["MultiLine 1"]],
|
|
["gjmultipoly", [2], ["MultiPoly 1"]],
|
|
]
|
|
|
|
for test in tests:
|
|
|
|
rc, dstname = copy_shape_to_geojson(test[0], "/vsigzip/")
|
|
try:
|
|
assert rc, "Failed making copy of " + test[0] + ".shp"
|
|
|
|
rc = verify_geojson_copy(dstname, test[1], test[2])
|
|
assert rc, "Verification of copy of " + test[0] + ".shp failed"
|
|
finally:
|
|
if dstname:
|
|
dstname = dstname[len("/vsigzip/") :]
|
|
gdal.Unlink(dstname)
|
|
if gdal.VSIStatL(dstname + ".properties") is not None:
|
|
gdal.Unlink(dstname + ".properties")
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
def test_ogr_geojson_11():
|
|
|
|
ds = ogr.Open("data/geojson/srs_name.geojson")
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
assert ds.GetLayerCount() == 1, "Wrong number of layers"
|
|
|
|
lyr = ds.GetLayerByName("srs_name")
|
|
assert lyr is not None, "Missing layer called srs_name"
|
|
|
|
extent = (100.0, 102.0, 0.0, 1.0)
|
|
|
|
rc = validate_layer(lyr, "srs_name", 1, ogr.wkbGeometryCollection, 0, extent)
|
|
assert rc
|
|
|
|
ref = lyr.GetSpatialRef()
|
|
pcs = int(ref.GetAuthorityCode("PROJCS"))
|
|
assert pcs == 26915, "Spatial reference was not valid"
|
|
|
|
feature = lyr.GetNextFeature()
|
|
geometry = feature.GetGeometryRef().GetGeometryRef(0)
|
|
|
|
srs = geometry.GetSpatialReference()
|
|
pcs = int(srs.GetAuthorityCode("PROJCS"))
|
|
assert pcs == 26916, "Spatial reference for individual geometry was not valid"
|
|
|
|
lyr = None
|
|
|
|
|
|
###############################################################################
|
|
# Test DS passed as name with standalone "Point" feature object (#3377)
|
|
|
|
|
|
def test_ogr_geojson_12():
|
|
|
|
if os.name == "nt":
|
|
pytest.skip()
|
|
|
|
import test_cli_utilities
|
|
|
|
if test_cli_utilities.get_ogrinfo_path() is None:
|
|
pytest.skip()
|
|
|
|
ret = gdaltest.runexternal(
|
|
test_cli_utilities.get_ogrinfo_path()
|
|
+ ' -ro -al \'{"type": "Point","coordinates": [100.0, 0.0]}\''
|
|
)
|
|
assert ret.find(" POINT (100 0)") != -1
|
|
|
|
|
|
###############################################################################
|
|
# Test writing to stdout (#3381)
|
|
|
|
|
|
def test_ogr_geojson_13():
|
|
|
|
test = ["gjpoint", [1], ["Point 1"]]
|
|
|
|
rc, _ = copy_shape_to_geojson(test[0], "/vsistdout/")
|
|
assert rc, "Failed making copy of " + test[0] + ".shp"
|
|
|
|
|
|
###############################################################################
|
|
# Test reading & writing various degenerated geometries
|
|
|
|
|
|
@gdaltest.disable_exceptions()
|
|
def test_ogr_geojson_14():
|
|
|
|
with gdaltest.error_handler():
|
|
ds = ogr.Open("data/geojson/ogr_geojson_14.geojson")
|
|
lyr = ds.GetLayer(0)
|
|
|
|
try:
|
|
out_ds = ogr.GetDriverByName("GeoJSON").CreateDataSource(
|
|
"tmp/out_ogr_geojson_14.geojson"
|
|
)
|
|
out_lyr = out_ds.CreateLayer("lyr")
|
|
|
|
with gdaltest.error_handler():
|
|
for feat in lyr:
|
|
geom = feat.GetGeometryRef()
|
|
if geom is not None:
|
|
# print(geom)
|
|
out_feat = ogr.Feature(feature_def=out_lyr.GetLayerDefn())
|
|
out_feat.SetGeometry(geom)
|
|
out_lyr.CreateFeature(out_feat)
|
|
|
|
out_ds = None
|
|
finally:
|
|
try:
|
|
os.remove("tmp/out_ogr_geojson_14.geojson")
|
|
except OSError:
|
|
pass
|
|
|
|
|
|
###############################################################################
|
|
# Test Feature.ExportToJson (#3870)
|
|
|
|
|
|
def test_ogr_geojson_15():
|
|
|
|
feature_defn = ogr.FeatureDefn()
|
|
feature_defn.AddFieldDefn(ogr.FieldDefn("foo"))
|
|
field_defn = ogr.FieldDefn("boolfield", ogr.OFTInteger)
|
|
field_defn.SetSubType(ogr.OFSTBoolean)
|
|
feature_defn.AddFieldDefn(field_defn)
|
|
|
|
feature = ogr.Feature(feature_defn)
|
|
feature.SetField("foo", "bar")
|
|
feature.SetField("boolfield", True)
|
|
feature.SetFID(0)
|
|
|
|
geom = ogr.CreateGeometryFromWkt("POINT(1 2)")
|
|
feature.SetGeometry(geom)
|
|
|
|
try:
|
|
out = feature.ExportToJson()
|
|
except ImportError:
|
|
pytest.skip()
|
|
|
|
expected_out = """{"geometry": {"type": "Point", "coordinates": [1.0, 2.0]}, "type": "Feature", "properties": {"foo": "bar", "boolfield": true}, "id": 0}"""
|
|
|
|
if out != expected_out:
|
|
out_json = json.loads(out)
|
|
expected_out_json = json.loads(expected_out)
|
|
assert out_json == expected_out_json, out
|
|
|
|
out = feature.ExportToJson(as_object=True)
|
|
expected_out = {
|
|
"geometry": {"type": "Point", "coordinates": [1.0, 2.0]},
|
|
"type": "Feature",
|
|
"properties": {"foo": "bar", "boolfield": True},
|
|
"id": 0,
|
|
}
|
|
|
|
assert out == expected_out
|
|
|
|
|
|
###############################################################################
|
|
# Test reading files with no extension (#4314)
|
|
|
|
|
|
def test_ogr_geojson_20():
|
|
|
|
from glob import glob
|
|
|
|
geojson_files = glob("data/*.json")
|
|
geojson_files.extend(glob("data/*.geojson"))
|
|
|
|
for gj in geojson_files:
|
|
# create tmp file with no file extension
|
|
data = open(gj, "rb").read()
|
|
|
|
f = gdal.VSIFOpenL("/vsimem/testgj", "wb")
|
|
gdal.VSIFWriteL(data, 1, len(data), f)
|
|
gdal.VSIFCloseL(f)
|
|
|
|
with gdaltest.error_handler():
|
|
ds = ogr.Open("/vsimem/testgj")
|
|
if ds is None:
|
|
print(gj)
|
|
print(data.decode("LATIN1"))
|
|
pytest.fail("Failed to open datasource")
|
|
ds = None
|
|
|
|
gdal.Unlink("/vsimem/testgj")
|
|
|
|
|
|
###############################################################################
|
|
# Test reading output of geocouch spatiallist
|
|
|
|
|
|
def test_ogr_geojson_21():
|
|
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features":[
|
|
{"type": "Feature",
|
|
"geometry": {"type":"Point","coordinates":[1,2]},
|
|
"properties": {"_id":"aid", "_rev":"arev", "type":"Feature",
|
|
"properties":{"intvalue" : 2, "floatvalue" : 3.2, "strvalue" : "foo", "properties": { "foo": "bar"}}}}]}"""
|
|
)
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
lyr = ds.GetLayerByName("OGRGeoJSON")
|
|
|
|
feature = lyr.GetNextFeature()
|
|
ref_geom = ogr.CreateGeometryFromWkt("POINT (1 2)")
|
|
if (
|
|
feature.GetFieldAsString("_id") != "aid"
|
|
or feature.GetFieldAsString("_rev") != "arev"
|
|
or feature.GetFieldAsInteger("intvalue") != 2
|
|
or ogrtest.check_feature_geometry(feature, ref_geom) != 0
|
|
):
|
|
feature.DumpReadable()
|
|
pytest.fail()
|
|
|
|
lyr = None
|
|
ds = None
|
|
|
|
|
|
###############################################################################
|
|
# Same as ogr_geojson_21 with several features
|
|
|
|
|
|
def test_ogr_geojson_22():
|
|
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features":[
|
|
{"type": "Feature",
|
|
"geometry": {"type":"Point","coordinates":[1,2]},
|
|
"properties": {"_id":"aid", "_rev":"arev", "type":"Feature",
|
|
"properties":{"intvalue" : 2, "floatvalue" : 3.2, "strvalue" : "foo"}}},
|
|
{"type": "Feature",
|
|
"geometry": {"type":"Point","coordinates":[3,4]},
|
|
"properties": {"_id":"aid2", "_rev":"arev2", "type":"Feature",
|
|
"properties":{"intvalue" : 3.5, "str2value" : "bar"}}}]}"""
|
|
)
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
lyr = ds.GetLayerByName("OGRGeoJSON")
|
|
|
|
feature = lyr.GetNextFeature()
|
|
ref_geom = ogr.CreateGeometryFromWkt("POINT (1 2)")
|
|
if (
|
|
feature.GetFieldAsString("_id") != "aid"
|
|
or feature.GetFieldAsString("_rev") != "arev"
|
|
or feature.GetFieldAsDouble("intvalue") != 2
|
|
or ogrtest.check_feature_geometry(feature, ref_geom) != 0
|
|
):
|
|
feature.DumpReadable()
|
|
pytest.fail()
|
|
|
|
feature = lyr.GetNextFeature()
|
|
ref_geom = ogr.CreateGeometryFromWkt("POINT (3 4)")
|
|
if (
|
|
feature.GetFieldAsString("_id") != "aid2"
|
|
or feature.GetFieldAsString("_rev") != "arev2"
|
|
or feature.GetFieldAsDouble("intvalue") != 3.5
|
|
or feature.GetFieldAsString("str2value") != "bar"
|
|
or ogrtest.check_feature_geometry(feature, ref_geom) != 0
|
|
):
|
|
feature.DumpReadable()
|
|
pytest.fail()
|
|
|
|
lyr = None
|
|
ds = None
|
|
|
|
|
|
###############################################################################
|
|
# Write GeoJSON with bbox and test SRS writing&reading back
|
|
|
|
|
|
def test_ogr_geojson_23():
|
|
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource("/vsimem/ogr_geojson_23.json")
|
|
sr = osr.SpatialReference()
|
|
sr.ImportFromEPSG(4322)
|
|
lyr = ds.CreateLayer("foo", srs=sr, options=["WRITE_BBOX=YES"])
|
|
feat = ogr.Feature(lyr.GetLayerDefn())
|
|
feat.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 10)"))
|
|
lyr.CreateFeature(feat)
|
|
feat = ogr.Feature(lyr.GetLayerDefn())
|
|
feat.SetGeometry(ogr.CreateGeometryFromWkt("POINT(2 20)"))
|
|
lyr.CreateFeature(feat)
|
|
assert lyr.GetExtent() == (1.0, 2.0, 10.0, 20.0)
|
|
assert lyr.GetExtent(geom_field=0) == (1.0, 2.0, 10.0, 20.0)
|
|
assert lyr.GetExtent(geom_field=1, can_return_null=True) is None
|
|
lyr = None
|
|
ds = None
|
|
|
|
ds = ogr.Open("/vsimem/ogr_geojson_23.json")
|
|
lyr = ds.GetLayer(0)
|
|
sr_got = lyr.GetSpatialRef()
|
|
ds = None
|
|
|
|
sr.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER)
|
|
assert sr_got.IsSame(sr), "did not get expected SRS"
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_23.json", "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_23.json")
|
|
|
|
assert data.find('"bbox": [ 1, 10, 2, 20 ]') != -1, "did not find global bbox"
|
|
|
|
assert (
|
|
data.find('"bbox": [ 1.0, 10.0, 1.0, 10.0 ]') != -1
|
|
), "did not find first feature bbox"
|
|
|
|
|
|
###############################################################################
|
|
# Test alternate form of geojson
|
|
|
|
|
|
def test_ogr_geojson_24():
|
|
|
|
content = """loadGeoJSON({"layerFoo": { "type": "Feature",
|
|
"geometry": {
|
|
"type": "Point",
|
|
"coordinates": [2, 49]
|
|
},
|
|
"name": "bar"
|
|
},
|
|
"layerBar": { "type": "FeatureCollection", "features" : [ { "type": "Feature",
|
|
"geometry": {
|
|
"type": "Point",
|
|
"coordinates": [2, 49]
|
|
},
|
|
"other_name": "baz"
|
|
}]}})"""
|
|
|
|
for i in range(2):
|
|
if i == 0:
|
|
ds = ogr.Open(content)
|
|
else:
|
|
gdal.FileFromMemBuffer("/vsimem/ogr_geojson_24.js", content)
|
|
ds = ogr.Open("/vsimem/ogr_geojson_24.js")
|
|
gdal.Unlink("/vsimem/ogr_geojson_24.js")
|
|
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
lyr = ds.GetLayerByName("layerFoo")
|
|
assert lyr is not None, "cannot find layer"
|
|
|
|
feature = lyr.GetNextFeature()
|
|
ref_geom = ogr.CreateGeometryFromWkt("POINT (2 49)")
|
|
if (
|
|
feature.GetFieldAsString("name") != "bar"
|
|
or ogrtest.check_feature_geometry(feature, ref_geom) != 0
|
|
):
|
|
feature.DumpReadable()
|
|
pytest.fail()
|
|
|
|
lyr = ds.GetLayerByName("layerBar")
|
|
assert lyr is not None, "cannot find layer"
|
|
|
|
feature = lyr.GetNextFeature()
|
|
ref_geom = ogr.CreateGeometryFromWkt("POINT (2 49)")
|
|
if (
|
|
feature.GetFieldAsString("other_name") != "baz"
|
|
or ogrtest.check_feature_geometry(feature, ref_geom) != 0
|
|
):
|
|
feature.DumpReadable()
|
|
pytest.fail()
|
|
|
|
ds = None
|
|
|
|
|
|
###############################################################################
|
|
# Test 64bit support
|
|
|
|
|
|
def test_ogr_geojson_26():
|
|
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features":[
|
|
{"type": "Feature", "id": 1,
|
|
"geometry": {"type":"Point","coordinates":[1,2]},
|
|
"properties": { "intvalue" : 1, "int64" : 1234567890123, "intlist" : [1] }},
|
|
{"type": "Feature", "id": 1234567890123,
|
|
"geometry": {"type":"Point","coordinates":[3,4]},
|
|
"properties": { "intvalue" : 1234567890123, "intlist" : [1, 1234567890123] }},
|
|
]}"""
|
|
)
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
lyr = ds.GetLayerByName("OGRGeoJSON")
|
|
assert lyr.GetMetadataItem(ogr.OLMD_FID64) is not None
|
|
|
|
feature = lyr.GetNextFeature()
|
|
if feature.GetFID() != 1:
|
|
feature.DumpReadable()
|
|
pytest.fail()
|
|
if feature.GetField("intvalue") != 1:
|
|
feature.DumpReadable()
|
|
pytest.fail()
|
|
if feature.GetField("int64") != 1234567890123:
|
|
feature.DumpReadable()
|
|
pytest.fail()
|
|
|
|
feature = lyr.GetNextFeature()
|
|
if feature.GetFID() != 1234567890123:
|
|
feature.DumpReadable()
|
|
pytest.fail()
|
|
if feature.GetField("intvalue") != 1234567890123:
|
|
feature.DumpReadable()
|
|
pytest.fail()
|
|
if feature.GetField("intlist") != [1, 1234567890123]:
|
|
feature.DumpReadable()
|
|
pytest.fail()
|
|
|
|
lyr = None
|
|
ds = None
|
|
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource("/vsimem/ogr_geojson_26.json")
|
|
lyr = ds.CreateLayer("test")
|
|
lyr.CreateField(ogr.FieldDefn("int64", ogr.OFTInteger64))
|
|
lyr.CreateField(ogr.FieldDefn("int64list", ogr.OFTInteger64List))
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetFID(1234567890123)
|
|
f.SetField(0, 1234567890123)
|
|
f.SetFieldInteger64List(1, [1234567890123])
|
|
lyr.CreateFeature(f)
|
|
f = None
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_26.json", "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_26.json")
|
|
|
|
assert (
|
|
'{ "type": "Feature", "id": 1234567890123, "properties": { "int64": 1234567890123, "int64list": [ 1234567890123 ] }, "geometry": null }'
|
|
in data
|
|
)
|
|
|
|
|
|
###############################################################################
|
|
# Test workaround for 64bit values (returned as strings)
|
|
|
|
|
|
def test_ogr_geojson_27():
|
|
|
|
with gdaltest.error_handler():
|
|
# Warning 1: Integer values probably ranging out of 64bit integer range
|
|
# have been found. Will be clamped to INT64_MIN/INT64_MAX
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features":[
|
|
{"type": "Feature",
|
|
"geometry": {"type":"Point","coordinates":[1,2]},
|
|
"properties": { "intvalue" : 1 }},
|
|
{"type": "Feature",
|
|
"geometry": {"type":"Point","coordinates":[3,4]},
|
|
"properties": { "intvalue" : 12345678901231234567890123 }},
|
|
]}"""
|
|
)
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
lyr = ds.GetLayerByName("OGRGeoJSON")
|
|
|
|
feature = lyr.GetNextFeature()
|
|
if feature.GetField("intvalue") != 1:
|
|
feature.DumpReadable()
|
|
pytest.fail()
|
|
|
|
feature = lyr.GetNextFeature()
|
|
if feature.GetField("intvalue") != 9223372036854775807:
|
|
feature.DumpReadable()
|
|
pytest.fail()
|
|
|
|
lyr = None
|
|
ds = None
|
|
|
|
|
|
###############################################################################
|
|
# Test handling of huge coordinates (#5377)
|
|
|
|
|
|
def test_ogr_geojson_35():
|
|
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource("/vsimem/ogr_geojson_35.json")
|
|
lyr = ds.CreateLayer("foo")
|
|
feat = ogr.Feature(lyr.GetLayerDefn())
|
|
feat.SetFID(1)
|
|
geom = ogr.Geometry(ogr.wkbPoint)
|
|
geom.AddPoint_2D(-1.79769313486231571e308, -1.79769313486231571e308)
|
|
feat.SetGeometry(geom)
|
|
lyr.CreateFeature(feat)
|
|
|
|
with gdaltest.error_handler():
|
|
feat = ogr.Feature(lyr.GetLayerDefn())
|
|
feat.SetFID(2)
|
|
geom = ogr.Geometry(ogr.wkbPoint)
|
|
geom.AddPoint(-1.7e308 * 2, 1.7e308 * 2, 1.7e308 * 2) # evaluates to -inf, inf
|
|
feat.SetGeometry(geom)
|
|
lyr.CreateFeature(feat)
|
|
|
|
feat = ogr.Feature(lyr.GetLayerDefn())
|
|
feat.SetFID(3)
|
|
geom = ogr.Geometry(ogr.wkbLineString)
|
|
geom.AddPoint_2D(0, 0)
|
|
geom.AddPoint_2D(-1.7e308 * 2, 1.7e308 * 2) # evaluates to -inf, inf
|
|
feat.SetGeometry(geom)
|
|
lyr.CreateFeature(feat)
|
|
|
|
feat = ogr.Feature(lyr.GetLayerDefn())
|
|
feat.SetFID(4)
|
|
geom = ogr.Geometry(ogr.wkbPolygon)
|
|
geom2 = ogr.Geometry(ogr.wkbLinearRing)
|
|
geom2.AddPoint_2D(0, 0)
|
|
geom2.AddPoint_2D(-1.7e308 * 2, 1.7e308 * 2) # evaluates to -inf, inf
|
|
geom.AddGeometry(geom2)
|
|
feat.SetGeometry(geom)
|
|
lyr.CreateFeature(feat)
|
|
|
|
feat = ogr.Feature(lyr.GetLayerDefn())
|
|
feat.SetFID(5)
|
|
geom = ogr.Geometry(ogr.wkbMultiPoint)
|
|
geom2 = ogr.Geometry(ogr.wkbPoint)
|
|
geom2.AddPoint_2D(0, 0)
|
|
geom2 = ogr.Geometry(ogr.wkbPoint)
|
|
geom2.AddPoint_2D(-1.7e308 * 2, 1.7e308 * 2) # evaluates to -inf, inf
|
|
geom.AddGeometry(geom2)
|
|
feat.SetGeometry(geom)
|
|
lyr.CreateFeature(feat)
|
|
|
|
feat = ogr.Feature(lyr.GetLayerDefn())
|
|
feat.SetFID(6)
|
|
geom = ogr.Geometry(ogr.wkbMultiLineString)
|
|
geom2 = ogr.Geometry(ogr.wkbLineString)
|
|
geom2.AddPoint_2D(0, 0)
|
|
geom2 = ogr.Geometry(ogr.wkbLineString)
|
|
geom2.AddPoint_2D(-1.7e308 * 2, 1.7e308 * 2) # evaluates to -inf, inf
|
|
geom.AddGeometry(geom2)
|
|
feat.SetGeometry(geom)
|
|
lyr.CreateFeature(feat)
|
|
|
|
feat = ogr.Feature(lyr.GetLayerDefn())
|
|
feat.SetFID(7)
|
|
geom = ogr.Geometry(ogr.wkbMultiPolygon)
|
|
geom2 = ogr.Geometry(ogr.wkbPolygon)
|
|
geom3 = ogr.Geometry(ogr.wkbLinearRing)
|
|
geom3.AddPoint_2D(0, 0)
|
|
geom2.AddGeometry(geom3)
|
|
geom2 = ogr.Geometry(ogr.wkbPolygon)
|
|
geom3 = ogr.Geometry(ogr.wkbLinearRing)
|
|
geom3.AddPoint_2D(-1.7e308 * 2, 1.7e308 * 2) # evaluates to -inf, inf
|
|
geom2.AddGeometry(geom3)
|
|
geom.AddGeometry(geom2)
|
|
feat.SetGeometry(geom)
|
|
lyr.CreateFeature(feat)
|
|
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_35.json", "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_35.json")
|
|
|
|
assert "-1.79" in data and "e+308" in data
|
|
for ident in range(2, 8):
|
|
assert (
|
|
data.find(
|
|
'{ "type": "Feature", "id": %d, "properties": { }, "geometry": null }'
|
|
% ident
|
|
)
|
|
!= -1
|
|
)
|
|
|
|
|
|
###############################################################################
|
|
# Test reading file with UTF-8 BOM (which is supposed to be illegal in JSON...) (#5630)
|
|
|
|
|
|
def test_ogr_geojson_36():
|
|
|
|
ds = ogr.Open("data/geojson/point_with_utf8bom.json")
|
|
assert ds is not None, "Failed to open datasource"
|
|
ds = None
|
|
|
|
|
|
#########################################################################
|
|
# Test boolean type support
|
|
|
|
|
|
def test_ogr_geojson_37():
|
|
|
|
# Test read support
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection","features": [
|
|
{ "type": "Feature", "properties": { "bool" : false, "not_bool": false, "bool_list" : [false, true], "notbool_list" : [false, 3]}, "geometry": null },
|
|
{ "type": "Feature", "properties": { "bool" : true, "not_bool": 2, "bool_list" : [true] }, "geometry": null },
|
|
] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
feat_defn = lyr.GetLayerDefn()
|
|
assert (
|
|
feat_defn.GetFieldDefn(feat_defn.GetFieldIndex("bool")).GetType()
|
|
== ogr.OFTInteger
|
|
and feat_defn.GetFieldDefn(feat_defn.GetFieldIndex("bool")).GetSubType()
|
|
== ogr.OFSTBoolean
|
|
)
|
|
assert (
|
|
feat_defn.GetFieldDefn(feat_defn.GetFieldIndex("not_bool")).GetSubType()
|
|
== ogr.OFSTNone
|
|
)
|
|
assert (
|
|
feat_defn.GetFieldDefn(feat_defn.GetFieldIndex("bool_list")).GetType()
|
|
== ogr.OFTIntegerList
|
|
and feat_defn.GetFieldDefn(feat_defn.GetFieldIndex("bool_list")).GetSubType()
|
|
== ogr.OFSTBoolean
|
|
)
|
|
assert (
|
|
feat_defn.GetFieldDefn(feat_defn.GetFieldIndex("notbool_list")).GetType()
|
|
== ogr.OFTString
|
|
and feat_defn.GetFieldDefn(feat_defn.GetFieldIndex("notbool_list")).GetSubType()
|
|
== ogr.OFSTJSON
|
|
)
|
|
f = lyr.GetNextFeature()
|
|
if f.GetField("bool") != 0 or f.GetField("bool_list") != [0, 1]:
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
|
|
out_ds = ogr.GetDriverByName("GeoJSON").CreateDataSource(
|
|
"/vsimem/ogr_geojson_37.json"
|
|
)
|
|
out_lyr = out_ds.CreateLayer("test")
|
|
for i in range(feat_defn.GetFieldCount()):
|
|
out_lyr.CreateField(feat_defn.GetFieldDefn(i))
|
|
out_f = ogr.Feature(out_lyr.GetLayerDefn())
|
|
out_f.SetFrom(f)
|
|
out_lyr.CreateFeature(out_f)
|
|
out_ds = None
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_37.json", "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_37.json")
|
|
|
|
assert (
|
|
'"bool": false, "not_bool": 0, "bool_list": [ false, true ], "notbool_list": [ false, 3 ]'
|
|
in data
|
|
)
|
|
|
|
|
|
###############################################################################
|
|
# Test datetime/date/time type support
|
|
|
|
|
|
def test_ogr_geojson_38():
|
|
|
|
# Test read support
|
|
ds = gdal.OpenEx(
|
|
"""{"type": "FeatureCollection", "features": [
|
|
{ "type": "Feature", "properties": { "dt": "2014-11-20 12:34:56+0100", "dt2": "2014\\/11\\/20", "date":"2014\\/11\\/20", "time":"12:34:56", "no_dt": "2014-11-20 12:34:56+0100", "no_dt2": "2014-11-20 12:34:56+0100", "no_date": "2022/05/12 blah" }, "geometry": null },
|
|
{ "type": "Feature", "properties": { "dt": "2014\\/11\\/20", "dt2": "2014\\/11\\/20T12:34:56Z", "date":"2014-11-20", "time":"12:34:56", "no_dt": "foo", "no_dt2": 1 }, "geometry": null }
|
|
] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
feat_defn = lyr.GetLayerDefn()
|
|
assert (
|
|
feat_defn.GetFieldDefn(feat_defn.GetFieldIndex("dt")).GetType()
|
|
== ogr.OFTDateTime
|
|
)
|
|
assert (
|
|
feat_defn.GetFieldDefn(feat_defn.GetFieldIndex("dt2")).GetType()
|
|
== ogr.OFTDateTime
|
|
)
|
|
assert (
|
|
feat_defn.GetFieldDefn(feat_defn.GetFieldIndex("date")).GetType() == ogr.OFTDate
|
|
)
|
|
assert (
|
|
feat_defn.GetFieldDefn(feat_defn.GetFieldIndex("time")).GetType() == ogr.OFTTime
|
|
)
|
|
assert (
|
|
feat_defn.GetFieldDefn(feat_defn.GetFieldIndex("no_dt")).GetType()
|
|
== ogr.OFTString
|
|
)
|
|
assert (
|
|
feat_defn.GetFieldDefn(feat_defn.GetFieldIndex("no_dt2")).GetType()
|
|
== ogr.OFTString
|
|
)
|
|
assert (
|
|
feat_defn.GetFieldDefn(feat_defn.GetFieldIndex("no_date")).GetType()
|
|
== ogr.OFTString
|
|
)
|
|
f = lyr.GetNextFeature()
|
|
if (
|
|
f.GetField("dt") != "2014/11/20 12:34:56+01"
|
|
or f.GetField("dt2") != "2014/11/20 00:00:00"
|
|
or f.GetField("date") != "2014/11/20"
|
|
or f.GetField("time") != "12:34:56"
|
|
):
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
f = lyr.GetNextFeature()
|
|
if (
|
|
f.GetField("dt") != "2014/11/20 00:00:00"
|
|
or f.GetField("dt2") != "2014/11/20 12:34:56+00"
|
|
or f.GetField("date") != "2014/11/20"
|
|
or f.GetField("time") != "12:34:56"
|
|
):
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
|
|
tmpfilename = "/vsimem/out.json"
|
|
gdal.VectorTranslate(
|
|
tmpfilename, ds, options="-lco NATIVE_DATA=dummy"
|
|
) # dummy NATIVE_DATA so that input values are not copied directly
|
|
|
|
fp = gdal.VSIFOpenL(tmpfilename, "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink(tmpfilename)
|
|
|
|
assert (
|
|
'"dt": "2014-11-20T12:34:56+01:00", "dt2": "2014-11-20T00:00:00", "date": "2014-11-20", "time": "12:34:56"'
|
|
in data
|
|
), data
|
|
|
|
ds = gdal.OpenEx(
|
|
"""{"type": "FeatureCollection", "features": [
|
|
{ "type": "Feature", "properties": { "dt": "2014-11-20 12:34:56+0100", "dt2": "2014\\/11\\/20", "date":"2014\\/11\\/20", "time":"12:34:56", "no_dt": "2014-11-20 12:34:56+0100", "no_dt2": "2014-11-20 12:34:56+0100" }, "geometry": null }
|
|
] }""",
|
|
open_options=["DATE_AS_STRING=YES"],
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
feat_defn = lyr.GetLayerDefn()
|
|
for i in range(feat_defn.GetFieldCount()):
|
|
assert feat_defn.GetFieldDefn(i).GetType() == ogr.OFTString
|
|
|
|
|
|
###############################################################################
|
|
# Test id top-object level
|
|
|
|
|
|
@gdaltest.disable_exceptions()
|
|
def test_ogr_geojson_39():
|
|
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features": [
|
|
{ "type": "Feature", "id" : "foo", "properties": { "bar" : "baz" }, "geometry": null },
|
|
] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
feat_defn = lyr.GetLayerDefn()
|
|
assert (
|
|
feat_defn.GetFieldDefn(0).GetName() == "id"
|
|
and feat_defn.GetFieldDefn(0).GetType() == ogr.OFTString
|
|
)
|
|
feat = lyr.GetNextFeature()
|
|
if feat.GetField("id") != "foo" or feat.GetField("bar") != "baz":
|
|
feat.DumpReadable()
|
|
pytest.fail()
|
|
|
|
# Crazy case: properties.id has the precedence because we arbitrarily decided that...
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features": [
|
|
{ "type": "Feature", "id" : "foo", "properties": { "id" : 6 }, "geometry": null },
|
|
] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
feat_defn = lyr.GetLayerDefn()
|
|
assert (
|
|
feat_defn.GetFieldDefn(0).GetName() == "id"
|
|
and feat_defn.GetFieldDefn(0).GetType() == ogr.OFTInteger
|
|
)
|
|
feat = lyr.GetNextFeature()
|
|
if feat.GetField("id") != 6:
|
|
feat.DumpReadable()
|
|
pytest.fail()
|
|
|
|
# Same with 2 features
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features": [
|
|
{ "type": "Feature", "id" : "foo", "properties": { "id" : 6 }, "geometry": null },
|
|
{ "type": "Feature", "id" : "bar", "properties": { "id" : 7 }, "geometry": null }
|
|
] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
feat_defn = lyr.GetLayerDefn()
|
|
assert (
|
|
feat_defn.GetFieldDefn(0).GetName() == "id"
|
|
and feat_defn.GetFieldDefn(0).GetType() == ogr.OFTInteger
|
|
)
|
|
feat = lyr.GetNextFeature()
|
|
if feat.GetField("id") != 6:
|
|
feat.DumpReadable()
|
|
pytest.fail()
|
|
|
|
# Crazy case: properties.id has the precedence because we arbitrarily decided that...
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features": [
|
|
{ "type": "Feature", "id" : "foo", "properties": { "id" : "baz" }, "geometry": null },
|
|
] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
feat_defn = lyr.GetLayerDefn()
|
|
assert (
|
|
feat_defn.GetFieldDefn(0).GetName() == "id"
|
|
and feat_defn.GetFieldDefn(0).GetType() == ogr.OFTString
|
|
)
|
|
feat = lyr.GetNextFeature()
|
|
if feat.GetField("id") != "baz":
|
|
feat.DumpReadable()
|
|
pytest.fail()
|
|
|
|
# id and properties.ID (#6538)
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features": [
|
|
{ "type": "Feature", "id" : 1, "properties": { "ID": 2 }, "geometry": null },
|
|
] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
feat_defn = lyr.GetLayerDefn()
|
|
assert (
|
|
feat_defn.GetFieldDefn(0).GetName() == "ID"
|
|
and feat_defn.GetFieldDefn(0).GetType() == ogr.OFTInteger
|
|
)
|
|
feat = lyr.GetNextFeature()
|
|
if feat.GetFID() != 1 or feat.GetField("ID") != 2:
|
|
feat.DumpReadable()
|
|
pytest.fail()
|
|
|
|
# Test handling of duplicated id
|
|
gdal.ErrorReset()
|
|
with gdaltest.error_handler():
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features": [
|
|
{ "type": "Feature", "id" : 1, "properties": { "foo": "bar" }, "geometry": null },
|
|
{ "type": "Feature", "id" : 1, "properties": { "foo": "baz" }, "geometry": null },
|
|
{ "type": "Feature", "id" : 2, "properties": { "foo": "baw" }, "geometry": null }
|
|
] }"""
|
|
)
|
|
assert gdal.GetLastErrorMsg() != "", "expected warning"
|
|
lyr = ds.GetLayer(0)
|
|
feat_defn = lyr.GetLayerDefn()
|
|
feat = lyr.GetNextFeature()
|
|
if feat.GetFID() != 1 or feat.GetField("foo") != "bar":
|
|
feat.DumpReadable()
|
|
pytest.fail()
|
|
feat = lyr.GetNextFeature()
|
|
if feat.GetFID() != 2 or feat.GetField("foo") != "baz":
|
|
feat.DumpReadable()
|
|
pytest.fail()
|
|
feat = lyr.GetNextFeature()
|
|
if feat.GetFID() != 3 or feat.GetField("foo") != "baw":
|
|
feat.DumpReadable()
|
|
pytest.fail()
|
|
|
|
# negative id
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features": [
|
|
{ "type": "Feature", "id" : -1, "properties": { "foo": "bar" }, "geometry": null },
|
|
] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
feat_defn = lyr.GetLayerDefn()
|
|
assert (
|
|
feat_defn.GetFieldDefn(0).GetName() == "id"
|
|
and feat_defn.GetFieldDefn(0).GetType() == ogr.OFTInteger
|
|
)
|
|
feat = lyr.GetNextFeature()
|
|
if feat.GetField("id") != -1:
|
|
feat.DumpReadable()
|
|
pytest.fail()
|
|
|
|
# negative id 64bit
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features": [
|
|
{ "type": "Feature", "id" : -1234567890123, "properties": { "foo": "bar" }, "geometry": null },
|
|
{ "type": "Feature", "id" : -2, "properties": { "foo": "baz" }, "geometry": null },
|
|
] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
feat_defn = lyr.GetLayerDefn()
|
|
assert (
|
|
feat_defn.GetFieldDefn(0).GetName() == "id"
|
|
and feat_defn.GetFieldDefn(0).GetType() == ogr.OFTInteger64
|
|
)
|
|
feat = lyr.GetNextFeature()
|
|
if feat.GetField("id") != -1234567890123:
|
|
feat.DumpReadable()
|
|
pytest.fail()
|
|
|
|
# negative id
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features": [
|
|
{ "type": "Feature", "id" : -2, "properties": { "foo": "baz" }, "geometry": null },
|
|
{ "type": "Feature", "id" : -1234567890123, "properties": { "foo": "bar" }, "geometry": null },
|
|
] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
feat_defn = lyr.GetLayerDefn()
|
|
assert (
|
|
feat_defn.GetFieldDefn(0).GetName() == "id"
|
|
and feat_defn.GetFieldDefn(0).GetType() == ogr.OFTInteger64
|
|
)
|
|
feat = lyr.GetNextFeature()
|
|
if feat.GetField("id") != -2:
|
|
feat.DumpReadable()
|
|
pytest.fail()
|
|
|
|
# positive and then negative id
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features": [
|
|
{ "type": "Feature", "id" : 1, "properties": { "foo": "baz" }, "geometry": null },
|
|
{ "type": "Feature", "id" : -1, "properties": { "foo": "bar" }, "geometry": null },
|
|
] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
feat_defn = lyr.GetLayerDefn()
|
|
assert (
|
|
feat_defn.GetFieldDefn(0).GetName() == "id"
|
|
and feat_defn.GetFieldDefn(0).GetType() == ogr.OFTInteger
|
|
)
|
|
feat = lyr.GetNextFeature()
|
|
if feat.GetField("id") != 1:
|
|
feat.DumpReadable()
|
|
pytest.fail()
|
|
|
|
# mix of int and string id
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features": [
|
|
{ "type": "Feature", "id" : -2, "properties": { "foo": "baz" }, "geometry": null },
|
|
{ "type": "Feature", "id" : "str", "properties": { "foo": "bar" }, "geometry": null },
|
|
{ "type": "Feature", "id" : -3, "properties": { "foo": "baz" }, "geometry": null },
|
|
] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
feat_defn = lyr.GetLayerDefn()
|
|
assert (
|
|
feat_defn.GetFieldDefn(0).GetName() == "id"
|
|
and feat_defn.GetFieldDefn(0).GetType() == ogr.OFTString
|
|
)
|
|
feat = lyr.GetNextFeature()
|
|
if feat.GetField("id") != "-2":
|
|
feat.DumpReadable()
|
|
pytest.fail()
|
|
|
|
|
|
###############################################################################
|
|
# Test nested attributes
|
|
|
|
|
|
def test_ogr_geojson_40():
|
|
|
|
ds = gdal.OpenEx(
|
|
"""{
|
|
"type": "FeatureCollection",
|
|
"features" :
|
|
[
|
|
{
|
|
"type": "Feature",
|
|
"geometry": {
|
|
"type": "Point",
|
|
"coordinates": [ 2, 49 ]
|
|
},
|
|
"properties": {
|
|
"a_property": 1,
|
|
"some_object": {
|
|
"a_property": 1,
|
|
"another_property": 2
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "Feature",
|
|
"geometry": {
|
|
"type": "Point",
|
|
"coordinates": [ 2, 49 ]
|
|
},
|
|
"properties": {
|
|
"a_property": "foo",
|
|
"some_object": {
|
|
"a_property": 1,
|
|
"another_property": 2.34
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}""",
|
|
gdal.OF_VECTOR,
|
|
open_options=["FLATTEN_NESTED_ATTRIBUTES=YES", "NESTED_ATTRIBUTE_SEPARATOR=."],
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
feat = lyr.GetNextFeature()
|
|
feat = lyr.GetNextFeature()
|
|
if (
|
|
feat.GetField("a_property") != "foo"
|
|
or feat.GetField("some_object.a_property") != 1
|
|
or feat.GetField("some_object.another_property") != 2.34
|
|
):
|
|
feat.DumpReadable()
|
|
pytest.fail()
|
|
|
|
|
|
###############################################################################
|
|
# Test ogr.CreateGeometryFromJson()
|
|
|
|
|
|
def test_ogr_geojson_41():
|
|
|
|
# Check that by default we return a WGS 84 SRS
|
|
g = ogr.CreateGeometryFromJson("{ 'type': 'Point', 'coordinates' : [ 2, 49] }")
|
|
assert g.ExportToWkt() == "POINT (2 49)"
|
|
srs = g.GetSpatialReference()
|
|
g = None
|
|
|
|
assert srs.ExportToWkt().find("WGS 84") >= 0
|
|
|
|
# But if a crs object is set (allowed originally, but not recommended!), we use it
|
|
g = ogr.CreateGeometryFromJson(
|
|
'{ "type": "Point", "coordinates" : [ 2, 49], "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::4322" } } }'
|
|
)
|
|
srs = g.GetSpatialReference()
|
|
assert srs.ExportToWkt().find("4322") >= 0
|
|
|
|
# But if a crs object is set to null, set no crs
|
|
g = ogr.CreateGeometryFromJson(
|
|
'{ "type": "Point", "coordinates" : [ 2, 49], "crs": null }'
|
|
)
|
|
srs = g.GetSpatialReference()
|
|
assert not srs
|
|
|
|
|
|
###############################################################################
|
|
# Test Feature without geometry
|
|
|
|
|
|
def test_ogr_geojson_43():
|
|
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features":[
|
|
{"type": "Feature", "properties": {"foo": "bar"}}]}"""
|
|
)
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
lyr = ds.GetLayerByName("OGRGeoJSON")
|
|
|
|
feature = lyr.GetNextFeature()
|
|
if feature.GetFieldAsString("foo") != "bar":
|
|
feature.DumpReadable()
|
|
pytest.fail()
|
|
|
|
lyr = None
|
|
ds = None
|
|
|
|
|
|
###############################################################################
|
|
# Test null Feature (#6166)
|
|
|
|
|
|
def test_ogr_geojson_44():
|
|
|
|
with pytest.raises(Exception):
|
|
ogr.Open("""{"type": "FeatureCollection", "features":[ null ]}""")
|
|
|
|
|
|
###############################################################################
|
|
# Test native data support
|
|
|
|
|
|
def test_ogr_geojson_45():
|
|
|
|
# Test read support
|
|
content = """{"type": "FeatureCollection", "foo": "bar", "bar": "baz",
|
|
"features":[ { "type": "Feature", "foo": ["bar", "baz", 1.0, true, false,[],{}], "properties": { "myprop": "myvalue" }, "geometry": null } ]}"""
|
|
for i in range(2):
|
|
if i == 0:
|
|
ds = gdal.OpenEx(content, gdal.OF_VECTOR, open_options=["NATIVE_DATA=YES"])
|
|
else:
|
|
gdal.FileFromMemBuffer("/vsimem/ogr_geojson_45.json", content)
|
|
ds = gdal.OpenEx(
|
|
"/vsimem/ogr_geojson_45.json",
|
|
gdal.OF_VECTOR,
|
|
open_options=["NATIVE_DATA=YES"],
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
native_data = lyr.GetMetadataItem("NATIVE_DATA", "NATIVE_DATA")
|
|
assert native_data == '{ "foo": "bar", "bar": "baz" }'
|
|
native_media_type = lyr.GetMetadataItem("NATIVE_MEDIA_TYPE", "NATIVE_DATA")
|
|
assert native_media_type == "application/vnd.geo+json"
|
|
f = lyr.GetNextFeature()
|
|
native_data = f.GetNativeData()
|
|
if i == 0:
|
|
expected = [
|
|
'{ "type": "Feature", "foo": [ "bar", "baz", 1.000000, true, false, [ ], { } ], "properties": { "myprop": "myvalue" }, "geometry": null }',
|
|
'{ "type": "Feature", "foo": [ "bar", "baz", 1.0, true, false, [ ], { } ], "properties": { "myprop": "myvalue" }, "geometry": null }',
|
|
]
|
|
else:
|
|
expected = [
|
|
'{"type":"Feature","foo":["bar","baz",1.0,true,false,[],{}],"properties":{"myprop":"myvalue"},"geometry":null}'
|
|
]
|
|
assert native_data in expected
|
|
native_media_type = f.GetNativeMediaType()
|
|
assert native_media_type == "application/vnd.geo+json"
|
|
ds = None
|
|
if i == 1:
|
|
gdal.Unlink("/vsimem/ogr_geojson_45.json")
|
|
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource("/vsimem/ogr_geojson_45.json")
|
|
lyr = ds.CreateLayer(
|
|
"test",
|
|
options=[
|
|
'NATIVE_DATA={ "type": "ignored", "bbox": [ 0, 0, 0, 0 ], "foo": "bar", "bar": "baz", "features": "ignored" }',
|
|
"NATIVE_MEDIA_TYPE=application/vnd.geo+json",
|
|
],
|
|
)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
json_geom = """{ "type": "GeometryCollection", "foo_gc": "bar_gc", "geometries" : [
|
|
{ "type": "Point", "foo_point": "bar_point", "coordinates": [0,1,2, 3] },
|
|
{ "type": "LineString", "foo_linestring": "bar_linestring", "coordinates": [[0,1,2, 4]] },
|
|
{ "type": "MultiPoint", "foo_multipoint": "bar_multipoint", "coordinates": [[0,1,2, 5]] },
|
|
{ "type": "MultiLineString", "foo_multilinestring": "bar_multilinestring", "coordinates": [[[0,1,2, 6]]] },
|
|
{ "type": "Polygon", "foo_polygon": "bar_polygon", "coordinates": [[[0,1,2, 7]]] },
|
|
{ "type": "MultiPolygon", "foo_multipolygon": "bar_multipolygon", "coordinates": [[[[0,1,2, 8]]]] }
|
|
] }"""
|
|
f.SetNativeData(
|
|
'{ "type": "ignored", "bbox": "ignored", "properties" : "ignored", "foo_feature": "bar_feature", "geometry": %s }'
|
|
% json_geom
|
|
)
|
|
f.SetNativeMediaType("application/vnd.geo+json")
|
|
f.SetGeometry(ogr.CreateGeometryFromJson(json_geom))
|
|
lyr.CreateFeature(f)
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_45.json", "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_45.json")
|
|
|
|
assert (
|
|
'"bbox": [ 0, 1, 2, 0, 1, 2 ],' in data
|
|
and '"foo": "bar"' in data
|
|
and '"bar": "baz"' in data
|
|
and '"foo_feature": "bar_feature"' in data
|
|
and '"foo_gc": "bar_gc"' in data
|
|
and '"foo_point": "bar_point"' in data
|
|
and "3" in data
|
|
and '"foo_linestring": "bar_linestring"' in data
|
|
and "4" in data
|
|
and '"foo_multipoint": "bar_multipoint"' in data
|
|
and "5" in data
|
|
and '"foo_multilinestring": "bar_multilinestring"' in data
|
|
and "6" in data
|
|
and '"foo_polygon": "bar_polygon"' in data
|
|
and "7" in data
|
|
and '"foo_multipolygon": "bar_multipolygon"' in data
|
|
and "8" in data
|
|
)
|
|
|
|
# Test native support with string id
|
|
src_ds = gdal.OpenEx(
|
|
"""{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature",
|
|
"id": "foobarbaz",
|
|
"properties": {},
|
|
"geometry": null
|
|
}
|
|
]
|
|
}
|
|
""",
|
|
open_options=["NATIVE_DATA=YES"],
|
|
)
|
|
gdal.VectorTranslate("/vsimem/out.json", src_ds, format="GeoJSON")
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "id": "foobarbaz", "properties": { }, "geometry": null }
|
|
]
|
|
}
|
|
"""
|
|
assert json.loads(got) == json.loads(expected)
|
|
|
|
# Test native support with numeric id
|
|
src_ds = gdal.OpenEx(
|
|
"""{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature",
|
|
"id": 1234657890123,
|
|
"properties": {},
|
|
"geometry": null
|
|
}
|
|
]
|
|
}
|
|
""",
|
|
open_options=["NATIVE_DATA=YES"],
|
|
)
|
|
gdal.VectorTranslate("/vsimem/out.json", src_ds, format="GeoJSON")
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "id": 1234657890123, "properties": { }, "geometry": null }
|
|
]
|
|
}
|
|
"""
|
|
assert json.loads(got) == json.loads(expected)
|
|
|
|
|
|
###############################################################################
|
|
# Test that writing JSon content as value of a string field is serialized as it
|
|
|
|
|
|
def test_ogr_geojson_46():
|
|
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource("/vsimem/ogr_geojson_46.json")
|
|
lyr = ds.CreateLayer("test")
|
|
lyr.CreateField(ogr.FieldDefn("myprop"))
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f["myprop"] = '{ "a": "b" }'
|
|
lyr.CreateFeature(f)
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_46.json", "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_46.json")
|
|
|
|
assert '{ "myprop": { "a": "b" } }' in data
|
|
|
|
|
|
###############################################################################
|
|
# Test update support
|
|
|
|
|
|
@gdaltest.disable_exceptions()
|
|
def test_ogr_geojson_47():
|
|
|
|
# ERROR 6: Update from inline definition not supported
|
|
with gdaltest.error_handler():
|
|
ds = ogr.Open('{"type": "FeatureCollection", "features":[]}', update=1)
|
|
assert ds is None
|
|
|
|
gdal.FileFromMemBuffer(
|
|
"/vsimem/ogr_geojson_47.json",
|
|
"""{"type": "FeatureCollection", "foo": "bar",
|
|
"features":[ { "type": "Feature", "bar": "baz", "properties": { "myprop": "myvalue" }, "geometry": null } ]}""",
|
|
)
|
|
|
|
# Test read support
|
|
ds = ogr.Open("/vsimem/ogr_geojson_47.json", update=1)
|
|
lyr = ds.GetLayer(0)
|
|
f = lyr.GetNextFeature()
|
|
f.SetField("myprop", "another_value")
|
|
lyr.SetFeature(f)
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_47.json", "rb")
|
|
if fp is not None:
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
else:
|
|
data = None
|
|
|
|
# we don't want crs if there's no in the source
|
|
assert (
|
|
'"foo": "bar"' in data
|
|
and '"bar": "baz"' in data
|
|
and "crs" not in data
|
|
and '"myprop": "another_value"' in data
|
|
)
|
|
|
|
# Test append support
|
|
ds = ogr.Open("/vsimem/ogr_geojson_47.json", update=1)
|
|
lyr = ds.GetLayer(0)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 2)"))
|
|
lyr.CreateFeature(f)
|
|
if f.GetFID() != 1:
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(2 3)"))
|
|
lyr.CreateFeature(f)
|
|
f = lyr.GetNextFeature()
|
|
if f.GetFID() != 0:
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
ds = None
|
|
|
|
# Test append support
|
|
ds = ogr.Open("/vsimem/ogr_geojson_47.json", update=1)
|
|
lyr = ds.GetLayer(0)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(4 5)"))
|
|
lyr.CreateFeature(f)
|
|
f.SetField("myprop", "value_of_point_4_5")
|
|
lyr.SetFeature(f)
|
|
ds = None
|
|
|
|
ds = ogr.Open("/vsimem/ogr_geojson_47.json")
|
|
lyr = ds.GetLayer(0)
|
|
assert lyr.GetFeatureCount() == 4
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_47.json", "rb")
|
|
if fp is not None:
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
else:
|
|
data = None
|
|
|
|
# we don't want crs if there's no in the source
|
|
assert (
|
|
'"foo": "bar"' in data
|
|
and '"bar": "baz"' in data
|
|
and "crs" not in data
|
|
and '"myprop": "another_value"' in data
|
|
and '"myprop": "value_of_point_4_5"' in data
|
|
and "id" not in data
|
|
)
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_47.json")
|
|
|
|
# Test appending to empty features array
|
|
gdal.FileFromMemBuffer(
|
|
"/vsimem/ogr_geojson_47.json",
|
|
"""{ "type": "FeatureCollection", "features": []}""",
|
|
)
|
|
ds = ogr.Open("/vsimem/ogr_geojson_47.json", update=1)
|
|
lyr = ds.GetLayer(0)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
lyr.CreateFeature(f)
|
|
ds = None
|
|
ds = ogr.Open("/vsimem/ogr_geojson_47.json")
|
|
lyr = ds.GetLayer(0)
|
|
assert lyr.GetFeatureCount() == 1
|
|
ds = None
|
|
|
|
# Test appending to array ending with non feature
|
|
gdal.FileFromMemBuffer(
|
|
"/vsimem/ogr_geojson_47.json",
|
|
"""{ "type": "FeatureCollection", "features": [ null ]}""",
|
|
)
|
|
ds = ogr.Open("/vsimem/ogr_geojson_47.json", update=1)
|
|
lyr = ds.GetLayer(0)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
lyr.CreateFeature(f)
|
|
ds = None
|
|
ds = ogr.Open("/vsimem/ogr_geojson_47.json")
|
|
lyr = ds.GetLayer(0)
|
|
assert lyr.GetFeatureCount() == 1
|
|
ds = None
|
|
|
|
# Test appending to feature collection not ending with "features"
|
|
gdal.FileFromMemBuffer(
|
|
"/vsimem/ogr_geojson_47.json",
|
|
"""{ "type": "FeatureCollection", "features": [], "something": "else"}""",
|
|
)
|
|
ds = ogr.Open("/vsimem/ogr_geojson_47.json", update=1)
|
|
lyr = ds.GetLayer(0)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
lyr.CreateFeature(f)
|
|
ds = None
|
|
ds = ogr.Open("/vsimem/ogr_geojson_47.json")
|
|
lyr = ds.GetLayer(0)
|
|
assert lyr.GetFeatureCount() == 1
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_47.json", "rb")
|
|
if fp is not None:
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
else:
|
|
data = None
|
|
|
|
assert "something" in data
|
|
|
|
with gdaltest.config_option("OGR_GEOJSON_REWRITE_IN_PLACE", "YES"):
|
|
# Test appending to feature collection with "bbox"
|
|
gdal.FileFromMemBuffer(
|
|
"/vsimem/ogr_geojson_47.json",
|
|
"""{ "type": "FeatureCollection", "bbox": [0,0,0,0], "features": [ { "type": "Feature", "geometry": { "type": "Point", "coordinates": [0,0]} } ]}""",
|
|
)
|
|
ds = ogr.Open("/vsimem/ogr_geojson_47.json", update=1)
|
|
lyr = ds.GetLayer(0)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
lyr.CreateFeature(f)
|
|
ds = None
|
|
ds = ogr.Open("/vsimem/ogr_geojson_47.json")
|
|
lyr = ds.GetLayer(0)
|
|
assert lyr.GetFeatureCount() == 2
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_47.json", "rb")
|
|
if fp is not None:
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
else:
|
|
data = None
|
|
|
|
assert "bbox" in data
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_47.json")
|
|
|
|
|
|
###############################################################################
|
|
# Test update support with file that has a single feature not in a FeatureCollection
|
|
|
|
|
|
def test_ogr_geojson_48():
|
|
|
|
gdal.FileFromMemBuffer(
|
|
"/vsimem/ogr_geojson_48.json",
|
|
"""{ "type": "Feature", "bar": "baz", "bbox": [2,49,2,49], "properties": { "myprop": "myvalue" }, "geometry": {"type": "Point", "coordinates": [ 2, 49]} }""",
|
|
)
|
|
|
|
# Test read support
|
|
ds = ogr.Open("/vsimem/ogr_geojson_48.json", update=1)
|
|
lyr = ds.GetLayer(0)
|
|
f = lyr.GetNextFeature()
|
|
f.SetField("myprop", "another_value")
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (3 50)"))
|
|
lyr.SetFeature(f)
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_48.json", "rb")
|
|
if fp is not None:
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
else:
|
|
data = None
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_48.json")
|
|
|
|
# we don't want crs if there's no in the source
|
|
assert (
|
|
'"bar": "baz"' in data
|
|
and '"bbox": [ 3.0, 50.0, 3.0, 50.0 ]' in data
|
|
and "crs" not in data
|
|
and "FeatureCollection" not in data
|
|
and '"myprop": "another_value"' in data
|
|
)
|
|
|
|
|
|
###############################################################################
|
|
# Test ARRAY_AS_STRING
|
|
|
|
|
|
def test_ogr_geojson_49():
|
|
|
|
gdal.FileFromMemBuffer(
|
|
"/vsimem/ogr_geojson_49.json",
|
|
"""{ "type": "Feature", "properties": { "foo": ["bar"] }, "geometry": null }""",
|
|
)
|
|
|
|
# Test read support
|
|
ds = gdal.OpenEx(
|
|
"/vsimem/ogr_geojson_49.json", open_options=["ARRAY_AS_STRING=YES"]
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
assert lyr.GetLayerDefn().GetFieldDefn(0).GetType() == ogr.OFTString
|
|
f = lyr.GetNextFeature()
|
|
if f["foo"] != '[ "bar" ]':
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
ds = None
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_49.json")
|
|
|
|
|
|
###############################################################################
|
|
# Test that we serialize floating point values with enough significant figures
|
|
|
|
|
|
def test_ogr_geojson_50():
|
|
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource("/vsimem/ogr_geojson_50.json")
|
|
lyr = ds.CreateLayer("test")
|
|
lyr.CreateField(ogr.FieldDefn("val", ogr.OFTReal))
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f["val"] = 1.23456789012456
|
|
lyr.CreateFeature(f)
|
|
# To test smart rounding
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f["val"] = 5268.813
|
|
lyr.CreateFeature(f)
|
|
f = None
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_50.json", "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_50.json")
|
|
|
|
assert "1.23456789012456" in data or "5268.813 " in data
|
|
|
|
# If SIGNIFICANT_FIGURES is explicitly specified, and COORDINATE_PRECISION not,
|
|
# then it also applies to coordinates
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource("/vsimem/ogr_geojson_50.json")
|
|
lyr = ds.CreateLayer("test", options=["SIGNIFICANT_FIGURES=17"])
|
|
lyr.CreateField(ogr.FieldDefn("val", ogr.OFTReal))
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (0.0000123456789012456 0)"))
|
|
lyr.CreateFeature(f)
|
|
f = None
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_50.json", "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_50.json")
|
|
|
|
assert "1.23456789012456" in data or "-5" in data
|
|
|
|
# If SIGNIFICANT_FIGURES is explicitly specified, and COORDINATE_PRECISION too,
|
|
# then SIGNIFICANT_FIGURES only applies to non-coordinates floating point values.
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource("/vsimem/ogr_geojson_50.json")
|
|
lyr = ds.CreateLayer(
|
|
"test", options=["COORDINATE_PRECISION=15", "SIGNIFICANT_FIGURES=17"]
|
|
)
|
|
lyr.CreateField(ogr.FieldDefn("val", ogr.OFTReal))
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f["val"] = 1.23456789012456
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (0.0000123456789012456 0)"))
|
|
lyr.CreateFeature(f)
|
|
f = None
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_50.json", "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_50.json")
|
|
|
|
assert "0.00001234" in data and "1.23456789012456" in data
|
|
|
|
|
|
###############################################################################
|
|
# Test writing empty geometries
|
|
|
|
|
|
def test_ogr_geojson_51():
|
|
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource("/vsimem/ogr_geojson_51.json")
|
|
lyr = ds.CreateLayer("test")
|
|
lyr.CreateField(ogr.FieldDefn("id", ogr.OFTInteger))
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f["id"] = 1
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("POINT EMPTY"))
|
|
lyr.CreateFeature(f)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f["id"] = 2
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("LINESTRING EMPTY"))
|
|
lyr.CreateFeature(f)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f["id"] = 3
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON EMPTY"))
|
|
lyr.CreateFeature(f)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f["id"] = 4
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("MULTIPOINT EMPTY"))
|
|
lyr.CreateFeature(f)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f["id"] = 5
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("MULTILINESTRING EMPTY"))
|
|
lyr.CreateFeature(f)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f["id"] = 6
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("MULTIPOLYGON EMPTY"))
|
|
lyr.CreateFeature(f)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f["id"] = 7
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("GEOMETRYCOLLECTION EMPTY"))
|
|
lyr.CreateFeature(f)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_51.json", "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_51.json")
|
|
|
|
assert '{ "id": 1 }, "geometry": null' in data
|
|
|
|
assert (
|
|
'{ "id": 2 }, "geometry": { "type": "LineString", "coordinates": [ ] } }'
|
|
in data
|
|
)
|
|
|
|
assert (
|
|
'{ "id": 3 }, "geometry": { "type": "Polygon", "coordinates": [ ] } }' in data
|
|
)
|
|
|
|
assert (
|
|
'{ "id": 4 }, "geometry": { "type": "MultiPoint", "coordinates": [ ] } }'
|
|
in data
|
|
)
|
|
|
|
assert (
|
|
'{ "id": 5 }, "geometry": { "type": "MultiLineString", "coordinates": [ ] } }'
|
|
in data
|
|
)
|
|
|
|
assert (
|
|
'{ "id": 6 }, "geometry": { "type": "MultiPolygon", "coordinates": [ ] } }'
|
|
in data
|
|
)
|
|
|
|
assert (
|
|
'{ "id": 7 }, "geometry": { "type": "GeometryCollection", "geometries": [ ] } }'
|
|
in data
|
|
)
|
|
|
|
|
|
###############################################################################
|
|
# Test NULL type detection
|
|
|
|
|
|
def test_ogr_geojson_52():
|
|
|
|
ds = ogr.Open("data/geojson/nullvalues.geojson")
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
assert ds.GetLayerCount() == 1, "Wrong number of layers"
|
|
|
|
lyr = ds.GetLayerByName("nullvalues")
|
|
assert lyr is not None, "Missing layer called nullvalues"
|
|
|
|
fld = lyr.GetLayerDefn().GetFieldDefn(0)
|
|
assert fld.GetNameRef() == "int"
|
|
assert fld.GetType() == ogr.OFTInteger
|
|
fld = lyr.GetLayerDefn().GetFieldDefn(1)
|
|
assert fld.GetNameRef() == "string"
|
|
assert fld.GetType() == ogr.OFTString
|
|
fld = lyr.GetLayerDefn().GetFieldDefn(2)
|
|
assert fld.GetNameRef() == "double"
|
|
assert fld.GetType() == ogr.OFTReal
|
|
|
|
|
|
###############################################################################
|
|
# Test that M is ignored (this is a test of OGRLayer::CreateFeature() actually)
|
|
|
|
|
|
def test_ogr_geojson_53():
|
|
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource("/vsimem/ogr_geojson_53.json")
|
|
lyr = ds.CreateLayer("test")
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("POINT ZM (1 2 3 4)"))
|
|
lyr.CreateFeature(f)
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_53.json", "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_53.json")
|
|
|
|
assert '{ "type": "Point", "coordinates": [ 1.0, 2.0, 3.0 ] }' in data
|
|
|
|
|
|
###############################################################################
|
|
# Test NULL type detection when first value is null
|
|
|
|
|
|
def test_ogr_geojson_54():
|
|
|
|
ds = ogr.Open(
|
|
"""{
|
|
"type": "FeatureCollection",
|
|
|
|
"features": [
|
|
{ "type": "Feature", "properties": { "int": null, "string": null, "double": null, "dt" : null, "boolean": null, "null": null }, "geometry": null },
|
|
{ "type": "Feature", "properties": { "int": 168, "string": "string", "double": 1.23, "dt" : "2016-05-18T12:34:56Z", "boolean": true }, "geometry": null }
|
|
]
|
|
}
|
|
"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
|
|
fld = lyr.GetLayerDefn().GetFieldDefn(0)
|
|
assert fld.GetType() == ogr.OFTInteger
|
|
fld = lyr.GetLayerDefn().GetFieldDefn(1)
|
|
assert fld.GetType() == ogr.OFTString
|
|
fld = lyr.GetLayerDefn().GetFieldDefn(2)
|
|
assert fld.GetType() == ogr.OFTReal
|
|
fld = lyr.GetLayerDefn().GetFieldDefn(3)
|
|
assert fld.GetType() == ogr.OFTDateTime
|
|
fld = lyr.GetLayerDefn().GetFieldDefn(4)
|
|
assert fld.GetType() == ogr.OFTInteger
|
|
assert fld.GetSubType() == ogr.OFSTBoolean
|
|
assert fld.GetWidth() == 1
|
|
fld = lyr.GetLayerDefn().GetFieldDefn(5)
|
|
assert fld.GetType() == ogr.OFTString
|
|
|
|
|
|
###############################################################################
|
|
# Test RFC 7946
|
|
|
|
|
|
def read_file(filename):
|
|
f = gdal.VSIFOpenL(filename, "rb")
|
|
if f is None:
|
|
return None
|
|
content = gdal.VSIFReadL(1, 10000, f).decode("UTF-8")
|
|
gdal.VSIFCloseL(f)
|
|
return content
|
|
|
|
|
|
def test_ogr_geojson_55():
|
|
|
|
# Basic test for standard bbox and coordinate truncation
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"""{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "id": 123, "properties": {}, "geometry": { "type": "Point", "coordinates": [2.123456789, 49] } },
|
|
{ "type": "Feature", "id": 124, "properties": {}, "geometry": { "type": "Point", "coordinates": [3, 50] } }
|
|
]
|
|
}""",
|
|
options="-f GeoJSON -lco RFC7946=YES -lco WRITE_BBOX=YES -preserve_fid",
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"bbox": [ 2.1234568, 49.0000000, 3.0000000, 50.0000000 ],
|
|
"features": [
|
|
{ "type": "Feature", "id": 123, "properties": { }, "bbox": [ 2.1234568, 49.0, 2.1234568, 49.0 ], "geometry": { "type": "Point", "coordinates": [ 2.1234568, 49.0 ] } },
|
|
{ "type": "Feature", "id": 124, "properties": { }, "bbox": [ 3.0, 50.0, 3.0, 50.0 ], "geometry": { "type": "Point", "coordinates": [ 3.0, 50.0 ] } }
|
|
]
|
|
}
|
|
"""
|
|
assert json.loads(got) == json.loads(expected)
|
|
|
|
# Test polygon winding order
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"""{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [[[2,49],[3,49],[3,50],[2,50],[2,49]],[[2.1,49.1],[2.1,49.9],[2.9,49.9],[2.9,49.1],[2.1,49.1]]] } },
|
|
{ "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [[[2,49],[2,50],[3,50],[3,49],[2,49]],[[2.1,49.1],[2.9,49.1],[2.9,49.9],[2.1,49.9],[2.1,49.1]]] } },
|
|
]
|
|
}
|
|
""",
|
|
format="GeoJSON",
|
|
layerCreationOptions=["RFC7946=YES", "WRITE_BBOX=YES"],
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"bbox": [ 2.0000000, 49.0000000, 3.0000000, 50.0000000 ],
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 2.0, 49.0, 3.0, 50.0 ], "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.0, 49.0 ], [ 3.0, 49.0 ], [ 3.0, 50.0 ], [ 2.0, 50.0 ], [ 2.0, 49.0 ] ], [ [ 2.1, 49.1 ], [ 2.1, 49.9 ], [ 2.9, 49.9 ], [ 2.9, 49.1 ], [ 2.1, 49.1 ] ] ] } },
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 2.0, 49.0, 3.0, 50.0 ], "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.0, 49.0 ], [ 3.0, 49.0 ], [ 3.0, 50.0 ], [ 2.0, 50.0 ], [ 2.0, 49.0 ] ], [ [ 2.1, 49.1 ], [ 2.1, 49.9 ], [ 2.9, 49.9 ], [ 2.9, 49.1 ], [ 2.1, 49.1 ] ] ] } }
|
|
]
|
|
}
|
|
"""
|
|
assert json.loads(got) == json.loads(expected)
|
|
|
|
# Test foreign member
|
|
src_ds = gdal.OpenEx(
|
|
"""{
|
|
"type": "FeatureCollection",
|
|
"coordinates": "should not be found in output",
|
|
"geometries": "should not be found in output",
|
|
"geometry": "should not be found in output",
|
|
"properties": "should not be found in output",
|
|
"valid": "should be in output",
|
|
"crs": "should not be found in output",
|
|
"bbox": [0,0,0,0],
|
|
"features": [
|
|
{ "type": "Feature",
|
|
"id": ["not expected as child of features"],
|
|
"coordinates": "should not be found in output",
|
|
"geometries": "should not be found in output",
|
|
"features": "should not be found in output",
|
|
"valid": "should be in output",
|
|
"properties": { "foo": "bar" },
|
|
"geometry": {
|
|
"type": "Point",
|
|
"bbox": [0,0,0,0],
|
|
"geometry": "should not be found in output",
|
|
"properties": "should not be found in output",
|
|
"features": "should not be found in output",
|
|
"valid": "should be in output",
|
|
"coordinates": [2,49]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
""",
|
|
open_options=["NATIVE_DATA=YES"],
|
|
)
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
src_ds,
|
|
format="GeoJSON",
|
|
layerCreationOptions=["RFC7946=YES"],
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"valid": "should be in output",
|
|
"bbox": [ 2.0000000, 49.0000000, 2.0000000, 49.0000000 ],
|
|
"features": [
|
|
{ "type": "Feature",
|
|
"valid": "should be in output",
|
|
"properties": { "id": [ "not expected as child of features" ], "foo": "bar" },
|
|
"geometry": { "type": "Point", "coordinates": [ 2.0, 49.0 ], "valid": "should be in output" } }
|
|
]
|
|
}
|
|
"""
|
|
assert json.loads(got) == json.loads(expected)
|
|
|
|
|
|
###############################################################################
|
|
# Test RFC 7946 (that require geos)
|
|
|
|
|
|
@pytest.mark.require_geos
|
|
def test_ogr_geojson_56():
|
|
|
|
# Test offsetting longitudes beyond antimeridian
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"""{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [182, 49] } },
|
|
{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [-183, 50] } },
|
|
{ "type": "Feature", "geometry": { "type": "LineString", "coordinates": [[-183, 51],[-182, 48]] } },
|
|
{ "type": "Feature", "geometry": { "type": "LineString", "coordinates": [[182, 52],[183, 47]] } },
|
|
{ "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [[[-183, 51],[-183, 48],[-182, 48],[-183, 48],[-183, 51]]] } },
|
|
{ "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [[[183, 51],[183, 48],[182, 48],[183, 48],[183, 51]]] } },
|
|
]
|
|
}""",
|
|
format="GeoJSON",
|
|
layerCreationOptions=["RFC7946=YES", "WRITE_BBOX=YES"],
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"bbox": [ -178.0000000, 47.0000000, 178.0000000, 52.0000000 ],
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ -178.0, 49.0, -178.0, 49.0 ], "geometry": { "type": "Point", "coordinates": [ -178.0, 49.0 ] } },
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 177.0, 50.0, 177.0, 50.0 ], "geometry": { "type": "Point", "coordinates": [ 177.0, 50.0 ] } },
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 177.0, 48.0, 178.0, 51.0 ], "geometry": { "type": "LineString", "coordinates": [ [ 177.0, 51.0 ], [ 178.0, 48.0 ] ] } },
|
|
{ "type": "Feature", "properties": { }, "bbox": [ -178.0, 47.0, -177.0, 52.0 ], "geometry": { "type": "LineString", "coordinates": [ [ -178.0, 52.0 ], [ -177.0, 47.0 ] ] } },
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 177.0, 48.0, 178.0, 51.0 ], "geometry": { "type": "Polygon", "coordinates": [ [ [ 177.0, 51.0 ], [ 177.0, 48.0 ], [ 178.0, 48.0 ], [ 177.0, 48.0 ], [ 177.0, 51.0 ] ] ] } },
|
|
{ "type": "Feature", "properties": { }, "bbox": [ -178.0, 48.0, -177.0, 51.0 ], "geometry": { "type": "Polygon", "coordinates": [ [ [ -177.0, 51.0 ], [ -177.0, 48.0 ], [ -178.0, 48.0 ], [ -177.0, 48.0 ], [ -177.0, 51.0 ] ] ] } }
|
|
]
|
|
}
|
|
"""
|
|
assert json.loads(got) == json.loads(expected)
|
|
|
|
# Test geometries across the antimeridian
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"""{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "geometry": { "type": "LineString", "coordinates": [[179, 51],[-179, 48]] } },
|
|
{ "type": "Feature", "geometry": { "type": "LineString", "coordinates": [[-179, 52],[179, 47]] } },
|
|
{ "type": "Feature", "geometry": { "type": "MultiLineString", "coordinates": [ [ [ 179.0, 51.0 ], [ 180.0, 49.5 ] ], [ [ -180.0, 49.5 ], [ -179.0, 48.0 ] ] ] } },
|
|
{ "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [[[177, 51],[-175, 51],[-175, 48],[177, 48],[177, 51]]] } },
|
|
{ "type": "Feature", "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 177.0, 51.0 ], [ 177.0, 48.0 ], [ 180.0, 48.0 ], [ 180.0, 51.0 ], [ 177.0, 51.0 ] ] ], [ [ [ -180.0, 51.0 ], [ -180.0, 48.0 ], [ -175.0, 48.0 ], [ -175.0, 51.0 ], [ -180.0, 51.0 ] ] ] ] } }
|
|
]
|
|
}""",
|
|
format="GeoJSON",
|
|
layerCreationOptions=["RFC7946=YES", "WRITE_BBOX=YES"],
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"bbox": [ 177.0000000, 47.0000000, -175.0000000, 52.0000000 ],
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 179.0, 48.0, -179.0, 51.0 ], "geometry": { "type": "MultiLineString", "coordinates": [ [ [ 179.0, 51.0 ], [ 180.0, 49.5 ] ], [ [ -180.0, 49.5 ], [ -179.0, 48.0 ] ] ] } },
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 179.0, 47.0, -179.0, 52.0 ], "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -179.0, 52.0 ], [ -180.0, 49.5 ] ], [ [ 180.0, 49.5 ], [ 179.0, 47.0 ] ] ] } },
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 179.0, 48.0, -179.0, 51.0 ], "geometry": { "type": "MultiLineString", "coordinates": [ [ [ 179.0, 51.0 ], [ 180.0, 49.5 ] ], [ [ -180.0, 49.5 ], [ -179.0, 48.0 ] ] ] } },
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 177.0, 48.0, -175.0, 51.0 ], "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 177.0, 51.0 ], [ 177.0, 48.0 ], [ 180.0, 48.0 ], [ 180.0, 51.0 ], [ 177.0, 51.0 ] ] ], [ [ [ -180.0, 51.0 ], [ -180.0, 48.0 ], [ -175.0, 48.0 ], [ -175.0, 51.0 ], [ -180.0, 51.0 ] ] ] ] } },
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 177.0, 48.0, -175.0, 51.0 ], "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 177.0, 51.0 ], [ 177.0, 48.0 ], [ 180.0, 48.0 ], [ 180.0, 51.0 ], [ 177.0, 51.0 ] ] ], [ [ [ -180.0, 51.0 ], [ -180.0, 48.0 ], [ -175.0, 48.0 ], [ -175.0, 51.0 ], [ -180.0, 51.0 ] ] ] ] } }
|
|
]
|
|
}
|
|
"""
|
|
|
|
j_got = json.loads(got)
|
|
j_expected = json.loads(expected)
|
|
assert j_got["bbox"] == j_expected["bbox"]
|
|
assert len(j_expected["features"]) == 5
|
|
assert (
|
|
ogrtest.check_feature_geometry(
|
|
ogr.CreateGeometryFromJson(json.dumps(j_got["features"][0]["geometry"])),
|
|
ogr.CreateGeometryFromJson(
|
|
json.dumps(j_expected["features"][0]["geometry"])
|
|
),
|
|
)
|
|
== 0
|
|
)
|
|
assert (
|
|
ogrtest.check_feature_geometry(
|
|
ogr.CreateGeometryFromJson(json.dumps(j_got["features"][1]["geometry"])),
|
|
ogr.CreateGeometryFromJson(
|
|
json.dumps(j_expected["features"][1]["geometry"])
|
|
),
|
|
)
|
|
== 0
|
|
)
|
|
assert (
|
|
ogrtest.check_feature_geometry(
|
|
ogr.CreateGeometryFromJson(json.dumps(j_got["features"][2]["geometry"])),
|
|
ogr.CreateGeometryFromJson(
|
|
json.dumps(j_expected["features"][2]["geometry"])
|
|
),
|
|
)
|
|
== 0
|
|
)
|
|
assert (
|
|
ogrtest.check_feature_geometry(
|
|
ogr.CreateGeometryFromJson(json.dumps(j_got["features"][3]["geometry"])),
|
|
ogr.CreateGeometryFromJson(
|
|
json.dumps(j_expected["features"][3]["geometry"])
|
|
),
|
|
)
|
|
== 0
|
|
)
|
|
assert (
|
|
ogrtest.check_feature_geometry(
|
|
ogr.CreateGeometryFromJson(json.dumps(j_got["features"][4]["geometry"])),
|
|
ogr.CreateGeometryFromJson(
|
|
json.dumps(j_expected["features"][4]["geometry"])
|
|
),
|
|
)
|
|
== 0
|
|
)
|
|
|
|
# Test polygon geometry that covers the whole world (#2833)
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"""{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "geometry": {"type":"Polygon","coordinates":[[[-180,-90.0],[180,-90.0],[180,90.0],[-180,90.0],[-180,-90.0]]]} }
|
|
]
|
|
}""",
|
|
format="GeoJSON",
|
|
layerCreationOptions=["RFC7946=YES", "WRITE_BBOX=YES"],
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"bbox": [ -180.0000000, -90.0000000, 180.0000000, 90.0000000 ],
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ -180.0, -90.0, 180.0, 90.0 ], "geometry": { "type": "Polygon", "coordinates": [ [ [ -180.0, -90.0 ], [ 180.0, -90.0 ], [ 180.0, 90.0 ], [ -180.0, 90.0 ], [ -180.0, -90.0 ] ] ] } }
|
|
]
|
|
}
|
|
"""
|
|
assert json.loads(got) == json.loads(expected)
|
|
|
|
# Test polygon geometry with one longitude at +/- 180deg (#6250)
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"""{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "geometry": {"type":"Polygon","coordinates":[[[-180,50],[179.5,50.0],[179.5,40],[-180,45],[-180,50]]]} }
|
|
]
|
|
}""",
|
|
format="GeoJSON",
|
|
layerCreationOptions=["RFC7946=YES", "WRITE_BBOX=YES"],
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ -180.0, 40.0, 179.5, 50.0 ], "geometry": { "type": "Polygon", "coordinates": [ [ [ -180.0, 50.0 ], [ -180.0, 45.0 ], [ 179.5, 40.0 ], [ 179.5, 50.0 ], [ -180.0, 50.0 ] ] ] } }
|
|
],
|
|
"bbox": [ -180.0000000, 40.0000000, 179.5000000, 50.0000000 ]
|
|
}
|
|
"""
|
|
assert json.loads(got) == json.loads(expected)
|
|
|
|
# Test WRAPDATELINE=NO (#6250)
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"""{"type":"LineString","coordinates":[[179,50],[-179,50]]}""",
|
|
format="GeoJSON",
|
|
layerCreationOptions=["RFC7946=YES", "WRITE_BBOX=YES", "WRAPDATELINE=NO"],
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ -179.0, 50.0, 179.0, 50.0 ], "geometry": { "type": "LineString", "coordinates": [ [ 179.0, 50.0 ], [ -179.0, 50.0 ] ] } }
|
|
],
|
|
"bbox": [ -179.0000000, 50.0000000, 179.0000000, 50.0000000 ]
|
|
}
|
|
"""
|
|
assert json.loads(got) == json.loads(expected)
|
|
|
|
|
|
###############################################################################
|
|
# Test RFC 7946 and reprojection
|
|
|
|
|
|
@pytest.mark.require_geos
|
|
def test_ogr_geojson_57():
|
|
|
|
# Standard case: EPSG:32662: WGS 84 / Plate Carre
|
|
src_ds = gdal.GetDriverByName("Memory").Create("", 0, 0, 0)
|
|
sr = osr.SpatialReference()
|
|
sr.SetFromUserInput(
|
|
"+proj=eqc +lat_ts=0 +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs"
|
|
)
|
|
lyr = src_ds.CreateLayer("test", srs=sr)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(
|
|
ogr.CreateGeometryFromWkt(
|
|
"POLYGON((2000000 2000000,2000000 -2000000,-2000000 -2000000,-2000000 2000000,2000000 2000000))"
|
|
)
|
|
)
|
|
lyr.CreateFeature(f)
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
src_ds,
|
|
format="GeoJSON",
|
|
layerCreationOptions=["WRITE_NAME=NO", "RFC7946=YES", "WRITE_BBOX=YES"],
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"bbox": [ -17.9663057, -17.9663057, 17.9663057, 17.9663057 ],
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ -17.9663057, -17.9663057, 17.9663057, 17.9663057 ], "geometry": { "type": "Polygon", "coordinates": [ [ [ 17.9663057, 17.9663057 ], [ -17.9663057, 17.9663057 ], [ -17.9663057, -17.9663057 ], [ 17.9663057, -17.9663057 ], [ 17.9663057, 17.9663057 ] ] ] } }
|
|
]
|
|
}
|
|
"""
|
|
assert json.loads(got) == json.loads(expected)
|
|
|
|
# Polar case: EPSG:3995: WGS 84 / Arctic Polar Stereographic
|
|
src_ds = gdal.GetDriverByName("Memory").Create("", 0, 0, 0)
|
|
sr = osr.SpatialReference()
|
|
sr.SetFromUserInput(
|
|
"+proj=stere +lat_0=90 +lat_ts=71 +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs"
|
|
)
|
|
lyr = src_ds.CreateLayer("test", srs=sr)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(
|
|
ogr.CreateGeometryFromWkt(
|
|
"POLYGON((2000000 2000000,2000000 -2000000,-2000000 -2000000,-2000000 2000000,2000000 2000000))"
|
|
)
|
|
)
|
|
lyr.CreateFeature(f)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(
|
|
ogr.CreateGeometryFromWkt(
|
|
"POLYGON((-2000000 -2000000,-1000000 -2000000,-1000000 2000000,-2000000 2000000,-2000000 -2000000))"
|
|
)
|
|
)
|
|
lyr.CreateFeature(f)
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
src_ds,
|
|
format="GeoJSON",
|
|
layerCreationOptions=["WRITE_NAME=NO", "RFC7946=YES", "WRITE_BBOX=YES"],
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"bbox": [ -180.0000000, 64.3861643, 180.0000000, 90.0000000 ],
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ -180.0, 64.3861643, 180.0, 90.0 ], "geometry": { "type": "Polygon", "coordinates": [ [ [ 135.0, 64.3861643 ], [ 180.0, 71.7425119 ], [ 180.0, 90.0 ], [ -180.0, 90.0 ], [ -180.0, 71.7425119 ], [ -135.0, 64.3861643 ], [ -45.0, 64.3861643 ], [ 45.0, 64.3861643 ], [ 135.0, 64.3861643 ] ] ] } },
|
|
{ "type": "Feature", "properties": { }, "bbox": [ -153.4349488, 64.3861643, -26.5650512, 69.6286694 ], "geometry": { "type": "Polygon", "coordinates": [ [ [ -45.0, 64.3861643 ], [ -26.5650512, 69.6286694 ], [ -153.4349488, 69.6286694 ], [ -135.0, 64.3861643 ], [ -45.0, 64.3861643 ] ] ] } }
|
|
]
|
|
}
|
|
"""
|
|
|
|
j_got = json.loads(got)
|
|
j_expected = json.loads(expected)
|
|
assert j_got["bbox"] == j_expected["bbox"]
|
|
assert len(j_expected["features"]) == 2
|
|
assert (
|
|
ogrtest.check_feature_geometry(
|
|
ogr.CreateGeometryFromJson(json.dumps(j_got["features"][0]["geometry"])),
|
|
ogr.CreateGeometryFromJson(
|
|
json.dumps(j_expected["features"][0]["geometry"])
|
|
),
|
|
)
|
|
== 0
|
|
)
|
|
assert (
|
|
ogrtest.check_feature_geometry(
|
|
ogr.CreateGeometryFromJson(json.dumps(j_got["features"][1]["geometry"])),
|
|
ogr.CreateGeometryFromJson(
|
|
json.dumps(j_expected["features"][1]["geometry"])
|
|
),
|
|
)
|
|
== 0
|
|
)
|
|
|
|
# Polar case: slice of spherical cap (not intersecting antimeridian, west hemisphere)
|
|
src_ds = gdal.GetDriverByName("Memory").Create("", 0, 0, 0)
|
|
sr = osr.SpatialReference()
|
|
sr.SetFromUserInput(
|
|
"+proj=stere +lat_0=90 +lat_ts=71 +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs"
|
|
)
|
|
lyr = src_ds.CreateLayer("test", srs=sr)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(
|
|
ogr.CreateGeometryFromWkt(
|
|
"POLYGON((-2000000 2000000,0 0,-2000000 -2000000,-2000000 2000000))"
|
|
)
|
|
)
|
|
lyr.CreateFeature(f)
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
src_ds,
|
|
format="GeoJSON",
|
|
layerCreationOptions=["WRITE_NAME=NO", "RFC7946=YES", "WRITE_BBOX=YES"],
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"bbox": [ -135.0000000, 64.3861643, -45.0000000, 90.0000000 ],
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ -135.0, 64.3861643, -45.0, 90.0 ], "geometry": { "type": "Polygon", "coordinates": [ [ [ -135.0, 64.3861643 ], [ -45.0, 64.3861643 ], [ -45.0, 90.0 ], [ -135.0, 90.0 ], [ -135.0, 64.3861643 ] ] ] } }
|
|
]
|
|
}
|
|
"""
|
|
assert json.loads(got) == json.loads(expected)
|
|
|
|
# Polar case: slice of spherical cap (not intersecting antimeridian, east hemisphere)
|
|
src_ds = gdal.GetDriverByName("Memory").Create("", 0, 0, 0)
|
|
sr = osr.SpatialReference()
|
|
sr.SetFromUserInput(
|
|
"+proj=stere +lat_0=90 +lat_ts=71 +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs"
|
|
)
|
|
lyr = src_ds.CreateLayer("test", srs=sr)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(
|
|
ogr.CreateGeometryFromWkt(
|
|
"MULTIPOLYGON(((2000000 2000000,0 0,2000000 -2000000,2000000 2000000)))"
|
|
)
|
|
)
|
|
lyr.CreateFeature(f)
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
src_ds,
|
|
format="GeoJSON",
|
|
layerCreationOptions=["WRITE_NAME=NO", "RFC7946=YES", "WRITE_BBOX=YES"],
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"bbox": [ 45.0000000, 64.3861643, 135.0000000, 90.0000000 ],
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 45.0, 64.3861643, 135.0, 90.0 ], "geometry": { "type": "Polygon", "coordinates": [ [ [ 135.0, 64.3861643 ], [ 135.0, 90.0 ], [ 45.0, 90.0 ], [ 45.0, 64.3861643 ], [ 135.0, 64.3861643 ] ] ] } }
|
|
]
|
|
}
|
|
"""
|
|
assert json.loads(got) == json.loads(expected)
|
|
|
|
# Polar case: slice of spherical cap crossing the antimeridian
|
|
src_ds = gdal.GetDriverByName("Memory").Create("", 0, 0, 0)
|
|
sr = osr.SpatialReference()
|
|
sr.SetFromUserInput(
|
|
"+proj=stere +lat_0=90 +lat_ts=71 +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs"
|
|
)
|
|
lyr = src_ds.CreateLayer("test", srs=sr)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(
|
|
ogr.CreateGeometryFromWkt(
|
|
"POLYGON((100000 100000,-100000 100000,0 0,100000 100000))"
|
|
)
|
|
)
|
|
lyr.CreateFeature(f)
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
src_ds,
|
|
format="GeoJSON",
|
|
layerCreationOptions=["WRITE_NAME=NO", "RFC7946=YES", "WRITE_BBOX=YES"],
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"bbox": [ 135.0000000, 88.6984598, -135.0000000, 90.0000000 ],
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 135.0, 88.6984598, -135.0, 90.0 ], "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 180.0, 89.0796531 ], [ 180.0, 90.0 ], [ 135.0, 88.6984598 ], [ 180.0, 89.0796531 ] ] ], [ [ [ -180.0, 90.0 ], [ -180.0, 89.0796531 ], [ -135.0, 88.6984598 ] ] ] ] } }
|
|
]
|
|
}
|
|
"""
|
|
expected_geos_overlay_ng = """{
|
|
"type": "FeatureCollection",
|
|
"bbox": [ 135.0000000, 88.6984598, -135.0000000, 90.0000000 ],
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 135.0, 88.6984598, -135.0, 90.0 ], "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -135.0, 88.6984598 ], [ -180.0, 90.0 ], [ -180.0, 89.0796531 ], [ -135.0, 88.6984598 ] ] ], [ [ [ 180.0, 90.0 ], [ 135.0, 88.6984598 ], [ 180.0, 89.0796531 ], [ 180.0, 90.0 ] ] ] ] } }
|
|
]
|
|
}"""
|
|
expected_geos_3_9_1 = """{
|
|
"type": "FeatureCollection",
|
|
"bbox": [ 135.0000000, 88.6984598, -135.0000000, 90.0000000 ],
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 135.0, 88.6984598, -135.0, 90.0 ], "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 135.0, 88.6984598 ], [ 180.0, 89.0796531 ], [ 180.0, 90.0 ], [ 135.0, 88.6984598 ] ] ], [ [ [ -135.0, 88.6984598 ], [ -180.0, 90.0 ], [ -180.0, 89.0796531 ], [ -135.0, 88.6984598 ] ] ] ] } }
|
|
]
|
|
}"""
|
|
assert (
|
|
json.loads(got) == json.loads(expected)
|
|
or json.loads(got) == json.loads(expected_geos_overlay_ng)
|
|
or json.loads(got) == json.loads(expected_geos_3_9_1)
|
|
), got
|
|
|
|
# Polar case: EPSG:3031: WGS 84 / Antarctic Polar Stereographic
|
|
src_ds = gdal.GetDriverByName("Memory").Create("", 0, 0, 0)
|
|
sr = osr.SpatialReference()
|
|
sr.SetFromUserInput(
|
|
"+proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs"
|
|
)
|
|
lyr = src_ds.CreateLayer("test", srs=sr)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(
|
|
ogr.CreateGeometryFromWkt(
|
|
"MULTIPOLYGON(((2000000 2000000,2000000 -2000000,-2000000 -2000000,-2000000 2000000,2000000 2000000)))"
|
|
)
|
|
)
|
|
lyr.CreateFeature(f)
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
src_ds,
|
|
format="GeoJSON",
|
|
layerCreationOptions=["WRITE_NAME=NO", "RFC7946=YES", "WRITE_BBOX=YES"],
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"bbox": [ -180.0000000, -90.0000000, 180.0000000, -64.3861643 ],
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ -180.0, -90.0, 180.0, -64.3861643 ], "geometry": { "type": "Polygon", "coordinates": [ [ [ 45.0, -64.3861643 ], [ -45.0, -64.3861643 ], [ -135.0, -64.3861643 ], [ -180.0, -71.7425119 ], [ -180.0, -90.0 ], [ 180.0, -90.0 ], [ 180.0, -71.7425119 ], [ 135.0, -64.3861643 ], [ 45.0, -64.3861643 ] ] ] } }
|
|
]
|
|
}
|
|
"""
|
|
j_got = json.loads(got)
|
|
j_expected = json.loads(expected)
|
|
assert j_got["bbox"] == j_expected["bbox"]
|
|
assert len(j_expected["features"]) == 1
|
|
assert (
|
|
ogrtest.check_feature_geometry(
|
|
ogr.CreateGeometryFromJson(json.dumps(j_got["features"][0]["geometry"])),
|
|
ogr.CreateGeometryFromJson(
|
|
json.dumps(j_expected["features"][0]["geometry"])
|
|
),
|
|
)
|
|
== 0
|
|
)
|
|
|
|
# Antimeridian case: EPSG:32660: WGS 84 / UTM zone 60N with polygon and line crossing
|
|
src_ds = gdal.GetDriverByName("Memory").Create("", 0, 0, 0)
|
|
sr = osr.SpatialReference()
|
|
sr.SetFromUserInput("+proj=utm +zone=60 +datum=WGS84 +units=m +no_defs")
|
|
lyr = src_ds.CreateLayer("test", srs=sr)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(
|
|
ogr.CreateGeometryFromWkt(
|
|
"POLYGON((670000 4000000,850000 4000000,850000 4100000,670000 4100000,670000 4000000))"
|
|
)
|
|
)
|
|
lyr.CreateFeature(f)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(
|
|
ogr.CreateGeometryFromWkt("MULTILINESTRING((670000 4000000,850000 4100000))")
|
|
)
|
|
lyr.CreateFeature(f)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("LINESTRING(670000 0,850000 0)"))
|
|
lyr.CreateFeature(f)
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
src_ds,
|
|
format="GeoJSON",
|
|
layerCreationOptions=["WRITE_NAME=NO", "RFC7946=YES", "WRITE_BBOX=YES"],
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"bbox": [ 178.5275649, 0.0000000, -179.0681936, 37.0308258 ],
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 178.8892102, 36.0816324, -179.0681936, 37.0308258 ], "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 180.0, 36.1071354 ], [ 180.0, 36.1071354 ], [ 180.0, 37.0082839 ], [ 180.0, 37.0082839 ], [ 178.9112998, 37.0308258 ], [ 178.8892102, 36.1298163 ], [ 180.0, 36.1071354 ] ] ], [ [ [ -180.0, 37.0082839 ], [ -180.0, 36.1071354 ], [ -180.0, 36.1071354 ], [ -179.1135277, 36.0816324 ], [ -179.0681936, 36.9810434 ], [ -180.0, 37.0082839 ] ] ] ] } },
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 178.8892102, 36.1298163, -179.0681936, 36.9810434 ], "geometry": { "type": "MultiLineString", "coordinates": [ [ [ 178.8892102, 36.1298163 ], [ 180.0, 36.5995612 ] ], [ [ -180.0, 36.5995612 ], [ -179.0681936, 36.9810434 ] ] ] } },
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 178.5275649, 0.0, -179.8562277, 0.0 ], "geometry": { "type": "MultiLineString", "coordinates": [ [ [ 178.5275649, 0.0 ], [ 180.0, 0.0 ] ], [ [ -180.0, 0.0 ], [ -179.8562277, 0.0 ] ] ] } }
|
|
]
|
|
}
|
|
"""
|
|
j_got = json.loads(got)
|
|
j_expected = json.loads(expected)
|
|
assert j_got["bbox"] == j_expected["bbox"]
|
|
assert len(j_expected["features"]) == 3
|
|
assert (
|
|
ogrtest.check_feature_geometry(
|
|
ogr.CreateGeometryFromJson(json.dumps(j_got["features"][0]["geometry"])),
|
|
ogr.CreateGeometryFromJson(
|
|
json.dumps(j_expected["features"][0]["geometry"])
|
|
),
|
|
)
|
|
== 0
|
|
)
|
|
assert (
|
|
ogrtest.check_feature_geometry(
|
|
ogr.CreateGeometryFromJson(json.dumps(j_got["features"][1]["geometry"])),
|
|
ogr.CreateGeometryFromJson(
|
|
json.dumps(j_expected["features"][1]["geometry"])
|
|
),
|
|
)
|
|
== 0
|
|
)
|
|
assert (
|
|
ogrtest.check_feature_geometry(
|
|
ogr.CreateGeometryFromJson(json.dumps(j_got["features"][2]["geometry"])),
|
|
ogr.CreateGeometryFromJson(
|
|
json.dumps(j_expected["features"][2]["geometry"])
|
|
),
|
|
)
|
|
== 0
|
|
)
|
|
|
|
# Antimeridian case: EPSG:32660: WGS 84 / UTM zone 60N with polygon on west of antimeridian
|
|
src_ds = gdal.GetDriverByName("Memory").Create("", 0, 0, 0)
|
|
sr = osr.SpatialReference()
|
|
sr.SetFromUserInput("+proj=utm +zone=60 +datum=WGS84 +units=m +no_defs")
|
|
lyr = src_ds.CreateLayer("test", srs=sr)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(
|
|
ogr.CreateGeometryFromWkt(
|
|
"POLYGON((670000 4000000,700000 4000000,700000 4100000,670000 4100000,670000 4000000))"
|
|
)
|
|
)
|
|
lyr.CreateFeature(f)
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
src_ds,
|
|
format="GeoJSON",
|
|
layerCreationOptions=["WRITE_NAME=NO", "RFC7946=YES", "WRITE_BBOX=YES"],
|
|
)
|
|
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
expected = """{
|
|
"type": "FeatureCollection",
|
|
"bbox": [ 178.8892102, 36.1240958, 179.2483693, 37.0308258 ],
|
|
"features": [
|
|
{ "type": "Feature", "properties": { }, "bbox": [ 178.8892102, 36.1240958, 179.2483693, 37.0308258 ], "geometry": { "type": "Polygon", "coordinates": [ [ [ 178.8892102, 36.1298163 ], [ 179.2223914, 36.1240958 ], [ 179.2483693, 37.0249155 ], [ 178.9112998, 37.0308258 ], [ 178.8892102, 36.1298163 ] ] ] } }
|
|
]
|
|
}
|
|
"""
|
|
assert json.loads(got) == json.loads(expected)
|
|
|
|
|
|
###############################################################################
|
|
# Test using the name member of FeatureCollection
|
|
|
|
|
|
def test_ogr_geojson_58():
|
|
|
|
ds = ogr.Open(
|
|
'{ "type": "FeatureCollection", "name": "layer_name", "features": []}'
|
|
)
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
lyr = ds.GetLayerByName("layer_name")
|
|
assert lyr is not None, "Missing layer called layer_name"
|
|
ds = None
|
|
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource("/vsimem/ogr_geojson_58.json")
|
|
lyr = ds.CreateLayer("foo")
|
|
ds = None
|
|
ds = ogr.Open("/vsimem/ogr_geojson_58.json")
|
|
assert ds.GetLayerByName("foo") is not None, "Missing layer called foo"
|
|
ds = None
|
|
gdal.Unlink("/vsimem/ogr_geojson_58.json")
|
|
|
|
|
|
###############################################################################
|
|
# Test using the description member of FeatureCollection
|
|
|
|
|
|
def test_ogr_geojson_59():
|
|
|
|
ds = ogr.Open(
|
|
'{ "type": "FeatureCollection", "description": "my_description", "features": []}'
|
|
)
|
|
assert ds is not None, "Failed to open datasource"
|
|
|
|
lyr = ds.GetLayer(0)
|
|
assert (
|
|
lyr.GetMetadataItem("DESCRIPTION") == "my_description"
|
|
), "Did not get DESCRIPTION"
|
|
ds = None
|
|
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource("/vsimem/ogr_geojson_59.json")
|
|
lyr = ds.CreateLayer("foo", options=["DESCRIPTION=my desc"])
|
|
ds = None
|
|
ds = ogr.Open("/vsimem/ogr_geojson_59.json")
|
|
lyr = ds.GetLayerByName("foo")
|
|
assert lyr.GetMetadataItem("DESCRIPTION") == "my desc", "Did not get DESCRIPTION"
|
|
ds = None
|
|
gdal.Unlink("/vsimem/ogr_geojson_59.json")
|
|
|
|
|
|
###############################################################################
|
|
# Test null vs unset field
|
|
|
|
|
|
def test_ogr_geojson_60():
|
|
|
|
ds = gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "features": [
|
|
{ "type": "Feature", "properties" : { "foo" : "bar" } },
|
|
{ "type": "Feature", "properties" : { "foo": null } },
|
|
{ "type": "Feature", "properties" : { } } ] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
f = lyr.GetNextFeature()
|
|
if f["foo"] != "bar":
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
f = lyr.GetNextFeature()
|
|
if not f.IsFieldNull("foo"):
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
f = lyr.GetNextFeature()
|
|
if f.IsFieldSet("foo"):
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
|
|
# Test writing side
|
|
gdal.VectorTranslate("/vsimem/ogr_geojson_60.json", ds, format="GeoJSON")
|
|
|
|
fp = gdal.VSIFOpenL("/vsimem/ogr_geojson_60.json", "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink("/vsimem/ogr_geojson_60.json")
|
|
assert (
|
|
'"properties": { "foo": "bar" }' in data
|
|
and '"properties": { "foo": null }' in data
|
|
and '"properties": { }' in data
|
|
)
|
|
|
|
|
|
###############################################################################
|
|
# Test corner cases
|
|
|
|
|
|
def test_ogr_geojson_61():
|
|
|
|
# Invalid JSon
|
|
gdal.FileFromMemBuffer(
|
|
"/vsimem/ogr_geojson_61.json",
|
|
"""{ "type": "FeatureCollection", "features": [""",
|
|
)
|
|
with pytest.raises(Exception):
|
|
ds = gdal.OpenEx("/vsimem/ogr_geojson_61.json")
|
|
gdal.Unlink("/vsimem/ogr_geojson_61.json")
|
|
|
|
# Invalid single geometry
|
|
with pytest.raises(Exception):
|
|
ds = gdal.OpenEx("""{ "type": "Point", "x" : { "coordinates" : null } } """)
|
|
|
|
# Empty property name
|
|
gdal.FileFromMemBuffer(
|
|
"/vsimem/ogr_geojson_61.json",
|
|
"""{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": {"": 1}, "geometry": null }] }""",
|
|
)
|
|
ds = gdal.OpenEx("/vsimem/ogr_geojson_61.json")
|
|
lyr = ds.GetLayer(0)
|
|
f = lyr.GetNextFeature()
|
|
assert f.GetField("") == 1
|
|
ds = None
|
|
gdal.Unlink("/vsimem/ogr_geojson_61.json")
|
|
|
|
|
|
###############################################################################
|
|
# Test crs object
|
|
|
|
|
|
def test_ogr_geojson_62():
|
|
|
|
# crs type=name tests
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"name" }, "features":[] }"""
|
|
)
|
|
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"name", "properties":null }, "features":[] }"""
|
|
)
|
|
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"name", "properties":1 }, "features":[] }"""
|
|
)
|
|
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"name", "properties":{"name":null} }, "features":[] }"""
|
|
)
|
|
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"name", "properties":{"name":1} }, "features":[] }"""
|
|
)
|
|
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"name", "properties":{"name":"x"} }, "features":[] }"""
|
|
)
|
|
|
|
ds = gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"name", "properties":{"name": "urn:ogc:def:crs:EPSG::32631"} }, "features":[] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
srs = lyr.GetSpatialRef()
|
|
assert srs.GetAuthorityCode(None) == "32631"
|
|
assert srs.GetDataAxisToSRSAxisMapping() == [1, 2]
|
|
|
|
# See https://github.com/OSGeo/gdal/issues/2035
|
|
ds = gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"name", "properties":{"name": "urn:ogc:def:crs:OGC:1.3:CRS84"} }, "features":[] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
srs = lyr.GetSpatialRef()
|
|
assert srs.GetAuthorityCode(None) == "4326"
|
|
assert srs.GetDataAxisToSRSAxisMapping() == [2, 1]
|
|
|
|
# crs type=EPSG (not even documented in GJ2008 spec!) tests. Just for coverage completeness
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"EPSG" }, "features":[] }"""
|
|
)
|
|
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"EPSG", "properties":null }, "features":[] }"""
|
|
)
|
|
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"EPSG", "properties":1 }, "features":[] }"""
|
|
)
|
|
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"EPSG", "properties":{"code":null} }, "features":[] }"""
|
|
)
|
|
|
|
with gdaltest.error_handler():
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"EPSG", "properties":{"code":1} }, "features":[] }"""
|
|
)
|
|
|
|
with gdaltest.error_handler():
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"EPSG", "properties":{"code":"x"} }, "features":[] }"""
|
|
)
|
|
|
|
ds = gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"EPSG", "properties":{"code": 32631} }, "features":[] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
srs = lyr.GetSpatialRef()
|
|
assert srs.ExportToWkt().find("32631") >= 0
|
|
|
|
# crs type=link tests
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"link" }, "features":[] }"""
|
|
)
|
|
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"link", "properties":null }, "features":[] }"""
|
|
)
|
|
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"link", "properties":1 }, "features":[] }"""
|
|
)
|
|
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"link", "properties":{"href":null} }, "features":[] }"""
|
|
)
|
|
|
|
with gdaltest.error_handler():
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"link", "properties":{"href":1} }, "features":[] }"""
|
|
)
|
|
|
|
with gdaltest.error_handler():
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"link", "properties":{"href": "1"} }, "features":[] }"""
|
|
)
|
|
|
|
# crs type=OGC (not even documented in GJ2008 spec!) tests. Just for coverage completeness
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"OGC" }, "features":[] }"""
|
|
)
|
|
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"OGC", "properties":null }, "features":[] }"""
|
|
)
|
|
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"OGC", "properties":1 }, "features":[] }"""
|
|
)
|
|
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"OGC", "properties":{"urn":null} }, "features":[] }"""
|
|
)
|
|
|
|
with gdaltest.error_handler():
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"OGC", "properties":{"urn":1} }, "features":[] }"""
|
|
)
|
|
|
|
with gdaltest.error_handler():
|
|
gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"OGC", "properties":{"urn":"x"} }, "features":[] }"""
|
|
)
|
|
|
|
ds = gdal.OpenEx(
|
|
"""{ "type": "FeatureCollection", "crs": { "type":"OGC", "properties":{"urn": "urn:ogc:def:crs:EPSG::32631"} }, "features":[] }"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
srs = lyr.GetSpatialRef()
|
|
assert srs.ExportToWkt().find("32631") >= 0
|
|
|
|
|
|
###############################################################################
|
|
# Extensive test of field type promotion
|
|
|
|
|
|
def test_ogr_geojson_63():
|
|
|
|
ds_ref = ogr.Open("data/geojson/test_type_promotion_ref.json")
|
|
lyr_ref = ds_ref.GetLayer(0)
|
|
ds = ogr.Open("data/geojson/test_type_promotion.json")
|
|
lyr = ds.GetLayer(0)
|
|
return ogrtest.compare_layers(lyr, lyr_ref)
|
|
|
|
|
|
###############################################################################
|
|
# Test exporting XYM / XYZM (#6935)
|
|
|
|
|
|
def test_ogr_geojson_64():
|
|
|
|
g = ogr.CreateGeometryFromWkt("POINT ZM(1 2 3 4)")
|
|
assert (
|
|
ogrtest.check_feature_geometry(
|
|
ogr.CreateGeometryFromJson(g.ExportToJson()),
|
|
ogr.CreateGeometryFromWkt("POINT Z(1 2 3)"),
|
|
)
|
|
== 0
|
|
)
|
|
|
|
g = ogr.CreateGeometryFromWkt("POINT M(1 2 3)")
|
|
assert (
|
|
ogrtest.check_feature_geometry(
|
|
ogr.CreateGeometryFromJson(g.ExportToJson()),
|
|
ogr.CreateGeometryFromWkt("POINT (1 2)"),
|
|
)
|
|
== 0
|
|
)
|
|
|
|
g = ogr.CreateGeometryFromWkt("LINESTRING ZM(1 2 3 4,5 6 7 8)")
|
|
assert (
|
|
ogrtest.check_feature_geometry(
|
|
ogr.CreateGeometryFromJson(g.ExportToJson()),
|
|
ogr.CreateGeometryFromWkt("LINESTRING Z(1 2 3,5 6 7)"),
|
|
)
|
|
== 0
|
|
)
|
|
|
|
g = ogr.CreateGeometryFromWkt("LINESTRING M(1 2 3,4 5 6)")
|
|
assert (
|
|
ogrtest.check_feature_geometry(
|
|
ogr.CreateGeometryFromJson(g.ExportToJson()),
|
|
ogr.CreateGeometryFromWkt("LINESTRING (1 2,4 5)"),
|
|
)
|
|
== 0
|
|
)
|
|
|
|
|
|
###############################################################################
|
|
# Test feature geometry CRS when CRS set on the FeatureCollection
|
|
# See https://github.com/r-spatial/sf/issues/449#issuecomment-319369945
|
|
|
|
|
|
def test_ogr_geojson_65():
|
|
|
|
ds = ogr.Open(
|
|
"""{
|
|
"type": "FeatureCollection",
|
|
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::32631" } },
|
|
"features": [{
|
|
"type": "Feature",
|
|
"geometry": {
|
|
"type": "Point",
|
|
"coordinates": [500000,4500000]},
|
|
"properties": {
|
|
}}]}"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
f = lyr.GetNextFeature()
|
|
srs = f.GetGeometryRef().GetSpatialReference()
|
|
pcs = int(srs.GetAuthorityCode("PROJCS"))
|
|
assert pcs == 32631, "Spatial reference for individual geometry was not valid"
|
|
|
|
|
|
###############################################################################
|
|
# Test features with properties not being a dictionary
|
|
|
|
|
|
def test_ogr_geojson_66():
|
|
|
|
ds = ogr.Open(
|
|
"""{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{
|
|
"type": "Feature",
|
|
"geometry": null,
|
|
"properties": null
|
|
},
|
|
{
|
|
"type": "Feature",
|
|
"geometry": null,
|
|
"properties": []
|
|
}
|
|
]}"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
assert lyr.GetLayerDefn().GetFieldCount() == 0
|
|
|
|
|
|
###############################################################################
|
|
# Test reading GeoJSON files starting with {"features":[{"geometry":.... (#7198)
|
|
|
|
|
|
def test_ogr_geojson_67():
|
|
|
|
ds = ogr.Open("data/geojson/grenada.geojson")
|
|
assert ds is not None
|
|
assert ds.GetDriver().GetName() == "GeoJSON"
|
|
lyr = ds.GetLayer(0)
|
|
assert lyr.GetFeatureCount() == 1
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
def test_ogr_geojson_id_field_and_id_type():
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"data/poly.shp",
|
|
options="-f GeoJSON -lco ID_TYPE=String -preserve_fid -limit 1 -fid 2",
|
|
)
|
|
got = read_file("/vsimem/out.json")
|
|
assert (
|
|
'"id": "2", "properties": { "AREA": 261752.781, "EAS_ID": 171, "PRFEDEA": "35043414" }'
|
|
in got
|
|
)
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"data/poly.shp",
|
|
options="-f GeoJSON -lco ID_TYPE=Integer -preserve_fid -limit 1 -fid 2",
|
|
)
|
|
got = read_file("/vsimem/out.json")
|
|
assert (
|
|
'"id": 2, "properties": { "AREA": 261752.781, "EAS_ID": 171, "PRFEDEA": "35043414" }'
|
|
in got
|
|
)
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"data/poly.shp",
|
|
format="GeoJSON",
|
|
layerCreationOptions=["ID_FIELD=EAS_ID"],
|
|
limit=1,
|
|
)
|
|
got = read_file("/vsimem/out.json")
|
|
assert (
|
|
'"id": 168, "properties": { "AREA": 215229.266, "PRFEDEA": "35043411" }' in got
|
|
)
|
|
|
|
src_ds = gdal.OpenEx("/vsimem/out.json", open_options=["NATIVE_DATA=YES"])
|
|
gdal.VectorTranslate("/vsimem/out2.json", src_ds, format="GeoJSON")
|
|
src_ds = None
|
|
got = read_file("/vsimem/out2.json")
|
|
gdal.Unlink("/vsimem/out2.json")
|
|
assert (
|
|
'"id": 168, "properties": { "AREA": 215229.266, "PRFEDEA": "35043411" }' in got
|
|
)
|
|
|
|
src_ds = gdal.OpenEx("/vsimem/out.json", open_options=["NATIVE_DATA=YES"])
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out2.json",
|
|
src_ds,
|
|
format="GeoJSON",
|
|
layerCreationOptions=["ID_TYPE=String"],
|
|
)
|
|
src_ds = None
|
|
got = read_file("/vsimem/out2.json")
|
|
gdal.Unlink("/vsimem/out2.json")
|
|
assert (
|
|
'"id": "168", "properties": { "AREA": 215229.266, "PRFEDEA": "35043411" }'
|
|
in got
|
|
)
|
|
|
|
src_ds = gdal.OpenEx("/vsimem/out.json", open_options=["NATIVE_DATA=YES"])
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out2.json",
|
|
src_ds,
|
|
format="GeoJSON",
|
|
layerCreationOptions=["ID_TYPE=Integer"],
|
|
)
|
|
src_ds = None
|
|
got = read_file("/vsimem/out2.json")
|
|
gdal.Unlink("/vsimem/out2.json")
|
|
assert (
|
|
'"id": 168, "properties": { "AREA": 215229.266, "PRFEDEA": "35043411" }' in got
|
|
)
|
|
|
|
gdal.Unlink("/vsimem/out.json")
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"data/poly.shp",
|
|
format="GeoJSON",
|
|
layerCreationOptions=["ID_FIELD=EAS_ID", "ID_TYPE=String"],
|
|
limit=1,
|
|
)
|
|
got = read_file("/vsimem/out.json")
|
|
assert (
|
|
'"id": "168", "properties": { "AREA": 215229.266, "PRFEDEA": "35043411" }'
|
|
in got
|
|
)
|
|
|
|
src_ds = gdal.OpenEx("/vsimem/out.json", open_options=["NATIVE_DATA=YES"])
|
|
gdal.VectorTranslate("/vsimem/out2.json", src_ds, format="GeoJSON")
|
|
src_ds = None
|
|
got = read_file("/vsimem/out2.json")
|
|
gdal.Unlink("/vsimem/out2.json")
|
|
assert (
|
|
'"id": "168", "properties": { "AREA": 215229.266, "PRFEDEA": "35043411" }'
|
|
in got
|
|
)
|
|
|
|
src_ds = gdal.OpenEx("/vsimem/out.json", open_options=["NATIVE_DATA=YES"])
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out2.json",
|
|
src_ds,
|
|
format="GeoJSON",
|
|
layerCreationOptions=["ID_TYPE=String"],
|
|
)
|
|
src_ds = None
|
|
got = read_file("/vsimem/out2.json")
|
|
gdal.Unlink("/vsimem/out2.json")
|
|
assert (
|
|
'"id": "168", "properties": { "AREA": 215229.266, "PRFEDEA": "35043411" }'
|
|
in got
|
|
)
|
|
|
|
src_ds = gdal.OpenEx("/vsimem/out.json", open_options=["NATIVE_DATA=YES"])
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out2.json",
|
|
src_ds,
|
|
format="GeoJSON",
|
|
layerCreationOptions=["ID_TYPE=Integer"],
|
|
)
|
|
src_ds = None
|
|
got = read_file("/vsimem/out2.json")
|
|
gdal.Unlink("/vsimem/out2.json")
|
|
assert (
|
|
'"id": 168, "properties": { "AREA": 215229.266, "PRFEDEA": "35043411" }' in got
|
|
)
|
|
|
|
gdal.Unlink("/vsimem/out.json")
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"data/poly.shp",
|
|
format="GeoJSON",
|
|
layerCreationOptions=["ID_FIELD=PRFEDEA"],
|
|
limit=1,
|
|
)
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
assert (
|
|
'"id": "35043411", "properties": { "AREA": 215229.266, "EAS_ID": 168 }' in got
|
|
)
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"data/poly.shp",
|
|
format="GeoJSON",
|
|
layerCreationOptions=["ID_FIELD=PRFEDEA", "ID_TYPE=Integer"],
|
|
limit=1,
|
|
)
|
|
got = read_file("/vsimem/out.json")
|
|
gdal.Unlink("/vsimem/out.json")
|
|
assert '"id": 35043411, "properties": { "AREA": 215229.266, "EAS_ID": 168 }' in got
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"data/poly.shp",
|
|
format="GeoJSON",
|
|
layerCreationOptions=["ID_GENERATE=YES"],
|
|
limit=1,
|
|
)
|
|
got = read_file("/vsimem/out.json")
|
|
assert (
|
|
'"id": 0, "properties": { "AREA": 215229.266, "EAS_ID": 168, "PRFEDEA": "35043411" }'
|
|
in got
|
|
)
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"data/poly.shp",
|
|
format="GeoJSON",
|
|
layerCreationOptions=["ID_GENERATE=YES", "ID_TYPE=Integer"],
|
|
limit=1,
|
|
)
|
|
got = read_file("/vsimem/out.json")
|
|
assert (
|
|
'"id": 0, "properties": { "AREA": 215229.266, "EAS_ID": 168, "PRFEDEA": "35043411" }'
|
|
in got
|
|
)
|
|
|
|
gdal.VectorTranslate(
|
|
"/vsimem/out.json",
|
|
"data/poly.shp",
|
|
format="GeoJSON",
|
|
layerCreationOptions=["ID_GENERATE=YES", "ID_TYPE=String"],
|
|
limit=1,
|
|
)
|
|
got = read_file("/vsimem/out.json")
|
|
assert (
|
|
'"id": "0", "properties": { "AREA": 215229.266, "EAS_ID": 168, "PRFEDEA": "35043411" }'
|
|
in got
|
|
)
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
@gdaltest.disable_exceptions()
|
|
def test_ogr_geojson_geom_export_failure():
|
|
|
|
g = ogr.CreateGeometryFromWkt("POINT EMPTY")
|
|
geojson = g.ExportToJson()
|
|
assert geojson is None
|
|
|
|
g = ogr.CreateGeometryFromWkt("GEOMETRYCOLLECTION(TIN EMPTY)")
|
|
geojson = json.loads(g.ExportToJson())
|
|
assert geojson == {"type": "GeometryCollection", "geometries": None}
|
|
|
|
g = ogr.Geometry(ogr.wkbLineString)
|
|
g.AddPoint_2D(float("nan"), 0)
|
|
with gdaltest.error_handler():
|
|
geojson = g.ExportToJson()
|
|
assert geojson is None
|
|
|
|
g = ogr.Geometry(ogr.wkbPolygon)
|
|
lr = ogr.Geometry(ogr.wkbLinearRing)
|
|
lr.AddPoint_2D(0, 0)
|
|
lr.AddPoint_2D(0, 1)
|
|
lr.AddPoint_2D(1, 1)
|
|
lr.AddPoint_2D(0, 0)
|
|
g.AddGeometry(lr)
|
|
lr = ogr.Geometry(ogr.wkbLinearRing)
|
|
lr.AddPoint_2D(0, 0)
|
|
lr.AddPoint_2D(float("nan"), 1)
|
|
lr.AddPoint_2D(1, 1)
|
|
lr.AddPoint_2D(0, 0)
|
|
g.AddGeometry(lr)
|
|
with gdaltest.error_handler():
|
|
geojson = g.ExportToJson()
|
|
assert geojson is None
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
def test_ogr_geojson_starting_with_crs():
|
|
|
|
ds = ogr.Open(
|
|
"""{
|
|
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::32631" } },
|
|
"type": "FeatureCollection",
|
|
"features": [{
|
|
"type": "Feature",
|
|
"geometry": {
|
|
"type": "Point",
|
|
"coordinates": [500000,4500000]},
|
|
"properties": {
|
|
}}]}"""
|
|
)
|
|
assert ds is not None
|
|
|
|
|
|
###############################################################################
|
|
# Test we properly flush the file in SyncToDisk() in append situations
|
|
|
|
|
|
def test_ogr_geojson_append_flush():
|
|
|
|
tmpfilename = "tmp/ogr_geojson_append_flush.json"
|
|
f = gdal.VSIFOpenL(tmpfilename, "wb")
|
|
content = """{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "properties": { "x": 1, "y": 2, "z": 3, "w": 4 }, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } } ] }"""
|
|
gdal.VSIFWriteL(content, 1, len(content), f)
|
|
gdal.VSIFCloseL(f)
|
|
|
|
ds = ogr.Open(tmpfilename, update=1)
|
|
lyr = ds.GetLayer(0)
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f["x"] = 10
|
|
lyr.CreateFeature(f)
|
|
lyr.SyncToDisk()
|
|
|
|
ds2 = ogr.Open(tmpfilename, update=1)
|
|
lyr = ds2.GetLayer(0)
|
|
lyr.GetNextFeature()
|
|
f = lyr.GetNextFeature()
|
|
assert f is not None and f["x"] == 10
|
|
|
|
ds = None
|
|
ds2 = None
|
|
gdal.Unlink(tmpfilename)
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
def test_ogr_geojson_empty_geometrycollection():
|
|
|
|
g = ogr.CreateGeometryFromJson('{"type": "GeometryCollection", "geometries": []}')
|
|
assert g.ExportToWkt() == "GEOMETRYCOLLECTION EMPTY"
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
def test_ogr_geojson_read_fields_with_different_case():
|
|
|
|
ds = ogr.Open(
|
|
"""{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "id": "my_id", "geometry": null, "properties":
|
|
{ "ID": "MY_ID", "x": "foo", "X": "FOO"} }
|
|
]}"""
|
|
)
|
|
|
|
lyr = ds.GetLayer(0)
|
|
f = lyr.GetNextFeature()
|
|
if (
|
|
f.GetField(0) != "my_id"
|
|
or f.GetField(1) != "MY_ID"
|
|
or f.GetField(2) != "foo"
|
|
or f.GetField(3) != "FOO"
|
|
):
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
|
|
|
|
###############################################################################
|
|
# Test bugfix for https://github.com/OSGeo/gdal/issues/1068
|
|
|
|
|
|
@pytest.mark.require_geos
|
|
def test_ogr_geojson_clip_geometries_rfc7946():
|
|
|
|
tmpfilename = "/vsimem/out.json"
|
|
gdal.VectorTranslate(
|
|
tmpfilename,
|
|
"""{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "geometry": {"type":"Polygon","coordinates":[[[-220,-20],[-220,30],[16,30],[16,-20],[-220,-20]]]} },
|
|
{ "type": "Feature", "geometry": {"type":"Polygon","coordinates":[[[220,40],[220,70],[-16,70],[-16,40],[220,40]]]} },
|
|
{ "type": "Feature", "geometry": {"type":"Polygon","coordinates":[[[170,-40],[170,-70],[-16,70],[-16,-40],[170,-40]]]} }
|
|
]
|
|
}""",
|
|
options="-f GeoJSON -lco RFC7946=YES",
|
|
)
|
|
|
|
ds = ogr.Open(tmpfilename)
|
|
lyr = ds.GetLayer(0)
|
|
|
|
f = lyr.GetNextFeature()
|
|
ref_geom = ogr.CreateGeometryFromWkt(
|
|
"MULTIPOLYGON (((-180 30,-180 -20,16 -20,16 30,-180 30)),((140 -20,180 -20,180 30,140 30,140 -20)))"
|
|
)
|
|
if ogrtest.check_feature_geometry(f, ref_geom) != 0:
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
|
|
f = lyr.GetNextFeature()
|
|
ref_geom = ogr.CreateGeometryFromWkt(
|
|
"MULTIPOLYGON (((180 40,180 70,-16 70,-16 40,180 40)),((-180 70,-180 40,-140 40,-140 70,-180 70)))"
|
|
)
|
|
if ogrtest.check_feature_geometry(f, ref_geom) != 0:
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
|
|
f = lyr.GetNextFeature()
|
|
ref_geom = ogr.CreateGeometryFromWkt(
|
|
"POLYGON ((170 -40,-16 -40,-16 70,170 -70,170 -40))"
|
|
)
|
|
if ogrtest.check_feature_geometry(f, ref_geom) != 0:
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
ds = None
|
|
|
|
gdal.Unlink(tmpfilename)
|
|
|
|
|
|
###############################################################################
|
|
# Test bugfix for https://github.com/OSGeo/gdal/issues/1109
|
|
|
|
|
|
def test_ogr_geojson_non_finite():
|
|
|
|
json_content = """{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "properties": { "inf_prop": infinity, "minus_inf_prop": -infinity, "nan_prop": nan }, "geometry": null }
|
|
]
|
|
}"""
|
|
with gdaltest.error_handler():
|
|
ds = ogr.Open(json_content)
|
|
if ds is None:
|
|
# Might fail with older libjson-c versions
|
|
pytest.skip()
|
|
lyr = ds.GetLayer(0)
|
|
f = lyr.GetNextFeature()
|
|
for i in range(3):
|
|
assert lyr.GetLayerDefn().GetFieldDefn(i).GetType() == ogr.OFTReal
|
|
|
|
if f["inf_prop"] != float("inf"):
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
if f["minus_inf_prop"] != float("-inf"):
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
if not math.isnan(f["nan_prop"]):
|
|
f.DumpReadable()
|
|
pytest.fail(str(f["nan_prop"]))
|
|
ds = None
|
|
|
|
tmpfilename = "/vsimem/out.json"
|
|
|
|
with gdaltest.error_handler():
|
|
gdal.VectorTranslate(tmpfilename, json_content, options="-f GeoJSON")
|
|
ds = ogr.Open(tmpfilename)
|
|
lyr = ds.GetLayer(0)
|
|
assert lyr.GetLayerDefn().GetFieldCount() == 0
|
|
ds = None
|
|
|
|
gdal.VectorTranslate(
|
|
tmpfilename, json_content, options="-f GeoJSON -lco WRITE_NON_FINITE_VALUES=YES"
|
|
)
|
|
ds = ogr.Open(tmpfilename)
|
|
lyr = ds.GetLayer(0)
|
|
assert lyr.GetLayerDefn().GetFieldCount() == 3
|
|
f = lyr.GetNextFeature()
|
|
if f["inf_prop"] != float("inf"):
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
if f["minus_inf_prop"] != float("-inf"):
|
|
f.DumpReadable()
|
|
pytest.fail()
|
|
if not math.isnan(f["nan_prop"]):
|
|
f.DumpReadable()
|
|
pytest.fail(str(f["nan_prop"]))
|
|
ds = None
|
|
|
|
gdal.Unlink(tmpfilename)
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
def test_ogr_geojson_random_reading_with_id():
|
|
|
|
json_content = """{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "id": 1, "properties": { "a": "a" }, "geometry": null },
|
|
{ "type": "Feature", "id": 2, "properties": { "a": "bc" }, "geometry": null }
|
|
]
|
|
}"""
|
|
tmpfilename = "/vsimem/temp.json"
|
|
gdal.FileFromMemBuffer(tmpfilename, json_content)
|
|
ds = ogr.Open(tmpfilename)
|
|
lyr = ds.GetLayer(0)
|
|
f1_ref = lyr.GetNextFeature()
|
|
f2_ref = lyr.GetNextFeature()
|
|
f1 = lyr.GetFeature(1)
|
|
f2 = lyr.GetFeature(2)
|
|
assert f1.Equal(f1_ref)
|
|
assert f2.Equal(f2_ref)
|
|
assert not lyr.GetFeature(3)
|
|
ds = None
|
|
gdal.Unlink(tmpfilename)
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
def test_ogr_geojson_random_reading_without_id():
|
|
|
|
json_content = """{
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{ "type": "Feature", "properties": { "a": "a" }, "geometry": null },
|
|
{ "type": "Feature", "properties": { "a": "bc" }, "geometry": null }
|
|
]
|
|
}"""
|
|
tmpfilename = "/vsimem/temp.json"
|
|
gdal.FileFromMemBuffer(tmpfilename, json_content)
|
|
ds = ogr.Open(tmpfilename)
|
|
lyr = ds.GetLayer(0)
|
|
f1_ref = lyr.GetNextFeature()
|
|
f2_ref = lyr.GetNextFeature()
|
|
f1 = lyr.GetFeature(0)
|
|
f2 = lyr.GetFeature(1)
|
|
assert f1.Equal(f1_ref)
|
|
assert f2.Equal(f2_ref)
|
|
assert not lyr.GetFeature(2)
|
|
ds = None
|
|
gdal.Unlink(tmpfilename)
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
def test_ogr_geojson_single_feature_random_reading_with_id():
|
|
|
|
json_content = """
|
|
{ "type": "Feature", "id": 1, "properties": { "a": "a" }, "geometry": null }
|
|
}"""
|
|
tmpfilename = "/vsimem/temp.json"
|
|
gdal.FileFromMemBuffer(tmpfilename, json_content)
|
|
ds = ogr.Open(tmpfilename)
|
|
lyr = ds.GetLayer(0)
|
|
f1_ref = lyr.GetNextFeature()
|
|
f1 = lyr.GetFeature(1)
|
|
assert f1.Equal(f1_ref)
|
|
ds = None
|
|
gdal.Unlink(tmpfilename)
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
def test_ogr_geojson_3D_geom_type():
|
|
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features":[
|
|
{"type": "Feature", "geometry": {"type":"Point","coordinates":[1,2,3]}, "properties": null},
|
|
{"type": "Feature", "geometry": {"type":"Point","coordinates":[1,2,4]}, "properties": null}
|
|
]}"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
assert lyr.GetGeomType() == ogr.wkbPoint25D
|
|
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features":[
|
|
{"type": "Feature", "geometry": {"type":"Point","coordinates":[1,2,3]}, "properties": null},
|
|
{"type": "Feature", "geometry": {"type":"Point","coordinates":[1,2]}, "properties": null}
|
|
]}"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
assert lyr.GetGeomType() == ogr.wkbPoint25D
|
|
|
|
ds = ogr.Open(
|
|
"""{"type": "FeatureCollection", "features":[
|
|
{"type": "Feature", "geometry": {"type":"Point","coordinates":[1,2]}, "properties": null},
|
|
{"type": "Feature", "geometry": {"type":"Point","coordinates":[1,2,4]}, "properties": null}
|
|
]}"""
|
|
)
|
|
lyr = ds.GetLayer(0)
|
|
assert lyr.GetGeomType() == ogr.wkbPoint25D
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
def test_ogr_geojson_update_in_loop():
|
|
|
|
tmpfilename = "/vsimem/temp.json"
|
|
|
|
# No explicit id
|
|
gdal.FileFromMemBuffer(
|
|
tmpfilename,
|
|
'{"type": "FeatureCollection", "name": "test", "features": [{ "type": "Feature", "properties": { "foo": 1 }, "geometry": null }, { "type": "Feature", "properties": { "foo": 2 }, "geometry": null }]}',
|
|
)
|
|
ds = gdal.OpenEx(tmpfilename, gdal.OF_VECTOR | gdal.GA_Update)
|
|
layer = ds.GetLayer()
|
|
fids = []
|
|
for feature in layer:
|
|
fids.append(feature.GetFID())
|
|
layer.SetFeature(feature)
|
|
assert fids == [0, 1]
|
|
ds = None
|
|
|
|
# Explicit id no holes
|
|
gdal.FileFromMemBuffer(
|
|
tmpfilename,
|
|
'{"type": "FeatureCollection", "name": "test", "features": [{ "type": "Feature", "id": 0, "properties": { "foo": 1 }, "geometry": null }, { "type": "Feature", "properties": { "foo": 2 }, "id": 1, "geometry": null }]}',
|
|
)
|
|
|
|
ds = gdal.OpenEx(tmpfilename, gdal.OF_VECTOR | gdal.GA_Update)
|
|
layer = ds.GetLayer()
|
|
fids = []
|
|
for feature in layer:
|
|
fids.append(feature.GetFID())
|
|
layer.SetFeature(feature)
|
|
assert fids == [0, 1]
|
|
ds = None
|
|
|
|
# Explicit id with holes
|
|
gdal.FileFromMemBuffer(
|
|
tmpfilename,
|
|
'{"type": "FeatureCollection", "name": "test", "features": [{ "type": "Feature", "id": 1, "properties": { "foo": 1 }, "geometry": null }, { "type": "Feature", "properties": { "foo": 2 }, "id": 3, "geometry": null }]}',
|
|
)
|
|
ds = gdal.OpenEx(tmpfilename, gdal.OF_VECTOR | gdal.GA_Update)
|
|
layer = ds.GetLayer()
|
|
fids = []
|
|
for feature in layer:
|
|
fids.append(feature.GetFID())
|
|
layer.SetFeature(feature)
|
|
assert fids == [1, 3]
|
|
ds = None
|
|
|
|
gdal.Unlink(tmpfilename)
|
|
|
|
|
|
###############################################################################
|
|
# Test fix for https://github.com/OSGeo/gdal/issues/2720
|
|
|
|
|
|
def test_ogr_geojson_starting_with_coordinates():
|
|
|
|
tmpfilename = "/vsimem/temp.json"
|
|
gdal.FileFromMemBuffer(
|
|
tmpfilename, '{ "coordinates": [' + (" " * 10000) + '2,49], "type": "Point"}'
|
|
)
|
|
ds = gdal.OpenEx(tmpfilename, gdal.OF_VECTOR)
|
|
assert ds is not None
|
|
|
|
gdal.Unlink(tmpfilename)
|
|
|
|
|
|
###############################################################################
|
|
# Test fix for https://github.com/OSGeo/gdal/issues/2787
|
|
|
|
|
|
def test_ogr_geojson_starting_with_geometry_coordinates():
|
|
|
|
tmpfilename = "/vsimem/temp.json"
|
|
gdal.FileFromMemBuffer(
|
|
tmpfilename,
|
|
'{ "geometry": {"coordinates": ['
|
|
+ (" " * 10000)
|
|
+ '2,49], "type": "Point"}, "type": "Feature", "properties": {} }',
|
|
)
|
|
ds = gdal.OpenEx(tmpfilename, gdal.OF_VECTOR)
|
|
assert ds is not None
|
|
|
|
gdal.Unlink(tmpfilename)
|
|
|
|
|
|
###############################################################################
|
|
# Test serialization of Float32 values
|
|
|
|
|
|
def test_ogr_geojson_write_float32():
|
|
def cast_as_float(x):
|
|
return struct.unpack("f", struct.pack("f", x))[0]
|
|
|
|
filename = "/vsimem/test_ogr_geojson_write_float32.json"
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource(filename)
|
|
lyr = ds.CreateLayer("foo")
|
|
|
|
fldn_defn = ogr.FieldDefn("float32", ogr.OFTReal)
|
|
fldn_defn.SetSubType(ogr.OFSTFloat32)
|
|
lyr.CreateField(fldn_defn)
|
|
|
|
fldn_defn = ogr.FieldDefn("float32list", ogr.OFTRealList)
|
|
fldn_defn.SetSubType(ogr.OFSTFloat32)
|
|
lyr.CreateField(fldn_defn)
|
|
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f["float32"] = cast_as_float(0.35)
|
|
f["float32list"] = [
|
|
cast_as_float(123.0),
|
|
cast_as_float(0.35),
|
|
cast_as_float(0.15),
|
|
cast_as_float(0.12345678),
|
|
cast_as_float(1.2345678e-15),
|
|
cast_as_float(1.2345678e15),
|
|
cast_as_float(0.123456789), # more decimals than Float32 can hold
|
|
]
|
|
lyr.CreateFeature(f)
|
|
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL(filename, "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink(filename)
|
|
|
|
data = data.replace("e+0", "e+").replace("e-0", "e-")
|
|
|
|
assert '"float32": 0.35,' in data
|
|
assert (
|
|
'"float32list": [ 123.0, 0.35, 0.15, 0.12345678, 1.2345678e-15, 1.2345678e+15, 0.12345679 ]'
|
|
in data
|
|
)
|
|
|
|
|
|
###############################################################################
|
|
# Test bugfix for #3172
|
|
|
|
|
|
def test_ogr_geojson_write_float_exponential_without_dot():
|
|
|
|
filename = "/vsimem/test_ogr_geojson_write_float_exponential_without_dot.json"
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource(filename)
|
|
lyr = ds.CreateLayer("foo")
|
|
|
|
fldn_defn = ogr.FieldDefn("float32", ogr.OFTReal)
|
|
fldn_defn.SetSubType(ogr.OFSTFloat32)
|
|
lyr.CreateField(fldn_defn)
|
|
|
|
fldn_defn = ogr.FieldDefn("float64", ogr.OFTReal)
|
|
lyr.CreateField(fldn_defn)
|
|
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f["float32"] = 1e-7
|
|
f["float64"] = 1e-8
|
|
lyr.CreateFeature(f)
|
|
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL(filename, "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink(filename)
|
|
|
|
# Check that the json can be parsed
|
|
json.loads(data)
|
|
|
|
|
|
###############################################################################
|
|
# Test bugfix for #3280
|
|
|
|
|
|
def test_ogr_geojson_feature_starting_with_big_properties():
|
|
|
|
filename = "/vsimem/test_ogr_geojson_feature_starting_with_big_properties.json"
|
|
gdal.FileFromMemBuffer(
|
|
filename,
|
|
'{"properties":{"foo":"%s"},"type":"Feature","geometry":null}' % ("x" * 10000),
|
|
)
|
|
assert ogr.Open(filename) is not None
|
|
gdal.Unlink(filename)
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
def test_ogr_geojson_export_geometry_axis_order():
|
|
|
|
# EPSG:4326 and lat,long data order
|
|
sr = osr.SpatialReference()
|
|
sr.ImportFromEPSG(4326)
|
|
sr.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
|
|
g = ogr.CreateGeometryFromWkt("POINT (49 2)")
|
|
g.AssignSpatialReference(sr)
|
|
before_wkt = g.ExportToWkt()
|
|
assert json.loads(g.ExportToJson()) == {"type": "Point", "coordinates": [2.0, 49.0]}
|
|
assert g.ExportToWkt() == before_wkt
|
|
|
|
# EPSG:4326 and long,lat data order
|
|
sr = osr.SpatialReference()
|
|
sr.ImportFromEPSG(4326)
|
|
sr.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER)
|
|
g = ogr.CreateGeometryFromWkt("POINT (2 49)")
|
|
g.AssignSpatialReference(sr)
|
|
assert json.loads(g.ExportToJson()) == {"type": "Point", "coordinates": [2.0, 49.0]}
|
|
|
|
# CRS84 with long,lat CRS and data order
|
|
sr = osr.SpatialReference()
|
|
sr.SetFromUserInput("OGC:CRS84")
|
|
g = ogr.CreateGeometryFromWkt("POINT (2 49)")
|
|
g.AssignSpatialReference(sr)
|
|
assert json.loads(g.ExportToJson()) == {"type": "Point", "coordinates": [2.0, 49.0]}
|
|
|
|
# Projected CRS with easting, northing order
|
|
sr = osr.SpatialReference()
|
|
sr.ImportFromEPSG(32631)
|
|
g = ogr.CreateGeometryFromWkt("POINT (2 49)")
|
|
g.AssignSpatialReference(sr)
|
|
assert json.loads(g.ExportToJson()) == {"type": "Point", "coordinates": [2.0, 49.0]}
|
|
|
|
# Projected CRS with northing, easting order
|
|
sr = osr.SpatialReference()
|
|
sr.ImportFromEPSG(2393)
|
|
sr.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
|
|
g = ogr.CreateGeometryFromWkt("POINT (49 2)")
|
|
g.AssignSpatialReference(sr)
|
|
assert json.loads(g.ExportToJson()) == {"type": "Point", "coordinates": [2.0, 49.0]}
|
|
|
|
# No CRS
|
|
g = ogr.CreateGeometryFromWkt("POINT (2 49)")
|
|
assert json.loads(g.ExportToJson()) == {"type": "Point", "coordinates": [2.0, 49.0]}
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
def test_ogr_geojson_sparse_fields():
|
|
|
|
ds = ogr.Open("data/geojson/sparse_fields.geojson")
|
|
lyr = ds.GetLayer(0)
|
|
lyr_defn = lyr.GetLayerDefn()
|
|
field_names = [
|
|
lyr_defn.GetFieldDefn(i).GetName() for i in range(lyr_defn.GetFieldCount())
|
|
]
|
|
assert field_names == ["C", "B", "A", "D", "E_prev", "E", "E_next", "F", "X"]
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
@pytest.mark.parametrize("filename", ["point.geojson", "featurecollection_point.json"])
|
|
def test_ogr_geojson_crs_4326(filename):
|
|
|
|
ds = ogr.Open("data/geojson/" + filename)
|
|
lyr = ds.GetLayer(0)
|
|
srs = lyr.GetSpatialRef()
|
|
assert srs.GetAuthorityCode(None) == "4326"
|
|
assert srs.GetDataAxisToSRSAxisMapping() == [2, 1]
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
@pytest.mark.parametrize("filename", ["pointz.json", "featurecollection_pointz.json"])
|
|
def test_ogr_geojson_crs_4979(filename):
|
|
|
|
ds = ogr.Open("data/geojson/" + filename)
|
|
lyr = ds.GetLayer(0)
|
|
srs = lyr.GetSpatialRef()
|
|
assert srs.GetAuthorityCode(None) == "4979"
|
|
assert srs.GetDataAxisToSRSAxisMapping() == [2, 1, 3]
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
def test_ogr_geojson_write_rfc7946_from_3D_crs():
|
|
|
|
srs_4979 = osr.SpatialReference()
|
|
srs_4979.ImportFromEPSG(4979)
|
|
srs_4979.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER)
|
|
|
|
srs_4326_5773 = osr.SpatialReference()
|
|
srs_4326_5773.SetFromUserInput("EPSG:4326+5773")
|
|
srs_4326_5773.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER)
|
|
|
|
ct = osr.CoordinateTransformation(srs_4979, srs_4326_5773)
|
|
ellipsoidal_height = 100
|
|
lon, lat, z = ct.TransformPoint(2, 49, ellipsoidal_height)
|
|
# If we have the egm96 grid, then z should be different from 100
|
|
|
|
filename = "/vsimem/out.geojson"
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource(filename)
|
|
lyr = ds.CreateLayer("out", srs=srs_4326_5773, options=["RFC7946=YES"])
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(%.18g %.18g %.18g)" % (lon, lat, z)))
|
|
lyr.CreateFeature(f)
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL(filename, "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
gdal.Unlink(filename)
|
|
|
|
# Check that we get back the ellipsoidal height
|
|
assert '"coordinates": [ 2.0, 49.0, 100.0' in data
|
|
|
|
|
|
###############################################################################
|
|
# Test effect of OGR_GEOJSON_MAX_OBJ_SIZE
|
|
|
|
|
|
@gdaltest.disable_exceptions()
|
|
def test_ogr_geojson_feature_large():
|
|
|
|
filename = "/vsimem/test_ogr_geojson_feature_large.json"
|
|
gdal.FileFromMemBuffer(
|
|
filename,
|
|
'{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"LineString","coordinates":[%s]}}]}'
|
|
% ",".join(["[0,0]" for _ in range(10 * 1024)]),
|
|
)
|
|
assert ogr.Open(filename) is not None
|
|
with gdaltest.config_option("OGR_GEOJSON_MAX_OBJ_SIZE", "0"):
|
|
assert ogr.Open(filename) is not None
|
|
with gdaltest.config_option("OGR_GEOJSON_MAX_OBJ_SIZE", "0.1"):
|
|
with gdaltest.error_handler():
|
|
assert ogr.Open(filename) is None
|
|
gdal.Unlink(filename)
|
|
|
|
|
|
###############################################################################
|
|
# Test reading http:// resource
|
|
|
|
|
|
@pytest.mark.require_curl()
|
|
def test_ogr_geojson_read_from_http():
|
|
|
|
import webserver
|
|
|
|
(webserver_process, webserver_port) = webserver.launch(
|
|
handler=webserver.DispatcherHttpHandler
|
|
)
|
|
if webserver_port == 0:
|
|
pytest.skip()
|
|
|
|
response = """{"type": "FeatureCollection", "features":[
|
|
{"type": "Feature", "geometry": {"type":"Point","coordinates":[1,2]}, "properties": null}]}"""
|
|
|
|
handler = webserver.SequentialHandler()
|
|
handler.add(
|
|
"GET",
|
|
"/foo",
|
|
200,
|
|
{},
|
|
response,
|
|
expected_headers={"Accept": "text/plain, application/json"},
|
|
)
|
|
|
|
try:
|
|
with webserver.install_http_handler(handler):
|
|
ds = ogr.Open("http://localhost:%d/foo" % webserver_port)
|
|
assert ds is not None
|
|
lyr = ds.GetLayer(0)
|
|
assert lyr.GetFeatureCount() == 1
|
|
finally:
|
|
webserver.server_stop(webserver_process, webserver_port)
|
|
|
|
|
|
###############################################################################
|
|
# Test ogr2ogr -nln with a input dataset being a GeoJSON file with a name
|
|
|
|
|
|
def test_ogr_geojson_ogr2ogr_nln_with_input_dataset_having_name():
|
|
|
|
filename = "/vsimem/test_ogr_geojson_feature_large.geojson"
|
|
gdal.VectorTranslate(
|
|
filename,
|
|
'{"type":"FeatureCollection","name":"to_be_overriden","features":[]}',
|
|
layerName="new_name",
|
|
)
|
|
ds = ogr.Open(filename)
|
|
assert ds.GetLayer(0).GetName() == "new_name"
|
|
ds = None
|
|
gdal.Unlink(filename)
|
|
|
|
|
|
###############################################################################
|
|
# Test reading a file with a id property with a mix of features where it is set
|
|
# and others none
|
|
|
|
|
|
@pytest.mark.parametrize("read_from_file", [True, False])
|
|
def test_ogr_geojson_ids_0_1_null_unset(read_from_file):
|
|
|
|
connection_name = "data/geojson/ids_0_1_null_unset.json"
|
|
if not read_from_file:
|
|
connection_name = open(connection_name, "rb").read().decode("ascii")
|
|
ds = ogr.Open(connection_name)
|
|
assert ds
|
|
lyr = ds.GetLayer(0)
|
|
f = lyr.GetNextFeature()
|
|
assert f.GetFID() == 0
|
|
assert f["id"] == 0
|
|
assert f["seq"] == 0
|
|
f = lyr.GetNextFeature()
|
|
assert f.GetFID() == 1
|
|
assert f["id"] == 1
|
|
assert f["seq"] == 1
|
|
f = lyr.GetNextFeature()
|
|
assert f.GetFID() == 2
|
|
assert f["id"] is None
|
|
assert f["seq"] == 2
|
|
f = lyr.GetNextFeature()
|
|
assert f.GetFID() == 3
|
|
assert not f.IsFieldSet("id")
|
|
assert f["seq"] == 3
|
|
f = lyr.GetNextFeature()
|
|
assert f is None
|
|
|
|
for i in range(4):
|
|
f = lyr.GetFeature(i)
|
|
assert f.GetFID() == i
|
|
assert f["seq"] == i
|
|
|
|
|
|
###############################################################################
|
|
# Test reading a file with a id property with a mix of features where it is set
|
|
# and others none, and a conflicting id
|
|
|
|
|
|
@gdaltest.disable_exceptions()
|
|
@pytest.mark.parametrize("read_from_file", [True, False])
|
|
def test_ogr_geojson_ids_0_1_null_1_null(read_from_file):
|
|
|
|
connection_name = "data/geojson/ids_0_1_null_1_null.json"
|
|
if not read_from_file:
|
|
connection_name = open(connection_name, "rb").read().decode("ascii")
|
|
with gdaltest.error_handler():
|
|
gdal.ErrorReset()
|
|
ds = ogr.Open(connection_name)
|
|
assert ds
|
|
if not read_from_file:
|
|
assert gdal.GetLastErrorType() == gdal.CE_Warning
|
|
lyr = ds.GetLayer(0)
|
|
f = lyr.GetNextFeature()
|
|
assert f.GetFID() == 0
|
|
assert f["id"] == 0
|
|
assert f["seq"] == 0
|
|
f = lyr.GetNextFeature()
|
|
assert f.GetFID() == 1
|
|
assert f["id"] == 1
|
|
assert f["seq"] == 1
|
|
f = lyr.GetNextFeature()
|
|
if read_from_file:
|
|
assert gdal.GetLastErrorType() == gdal.CE_Warning
|
|
assert f.GetFID() == 2
|
|
assert f["id"] is None
|
|
assert f["seq"] == 2
|
|
f = lyr.GetNextFeature()
|
|
assert f.GetFID() == 3
|
|
assert f["id"] == 1
|
|
assert f["seq"] == 3
|
|
f = lyr.GetNextFeature()
|
|
assert f.GetFID() == 4
|
|
assert f["id"] is None
|
|
assert f["seq"] == 4
|
|
f = lyr.GetNextFeature()
|
|
assert f is None
|
|
|
|
gdal.ErrorReset()
|
|
for i in range(5):
|
|
f = lyr.GetFeature(i)
|
|
assert f.GetFID() == i
|
|
assert f["seq"] == i
|
|
assert gdal.GetLastErrorType() == gdal.CE_None
|
|
|
|
|
|
###############################################################################
|
|
# Run test_ogrsf
|
|
|
|
|
|
def test_ogr_geojson_test_ogrsf():
|
|
|
|
import test_cli_utilities
|
|
|
|
if test_cli_utilities.get_test_ogrsf_path() is None:
|
|
pytest.skip()
|
|
|
|
ret = gdaltest.runexternal(
|
|
test_cli_utilities.get_test_ogrsf_path()
|
|
+ " -ro data/geojson/ids_0_1_null_1_null.json"
|
|
)
|
|
|
|
assert "INFO" in ret
|
|
assert "ERROR" not in ret
|
|
|
|
|
|
###############################################################################
|
|
# Test fix for https://github.com/OSGeo/gdal/issues/7313
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"properties",
|
|
[
|
|
["a_string", 42.0, {"a_field": "a_value"}],
|
|
["a_string", 42, {"a_field": "a_value"}],
|
|
["a_string", {"a_field": "a_value"}, 42],
|
|
[42, "a_string", {"a_field": "a_value"}],
|
|
[42, {"a_field": "a_value"}, "a_string"],
|
|
[{"a_field": "a_value"}, 42, "a_string"],
|
|
[{"a_field": "a_value"}, "a_string", 42],
|
|
],
|
|
)
|
|
def test_ogr_geojson_mixed_type_promotion(properties):
|
|
|
|
tmpfilename = "/vsimem/temp.json"
|
|
|
|
jdata = {"type": "FeatureCollection", "features": []}
|
|
|
|
for prop_val in properties:
|
|
jdata["features"].append({"type": "Feature", "properties": {"prop0": prop_val}})
|
|
|
|
gdal.FileFromMemBuffer(
|
|
tmpfilename,
|
|
json.dumps(jdata),
|
|
)
|
|
|
|
ds = gdal.OpenEx(tmpfilename, gdal.OF_VECTOR)
|
|
assert ds is not None
|
|
|
|
lyr = ds.GetLayer(0)
|
|
lyr_def = lyr.GetLayerDefn()
|
|
fld_def = lyr_def.GetFieldDefn(0)
|
|
assert fld_def.GetTypeName() == "String"
|
|
assert fld_def.GetSubType() == ogr.OFSTJSON
|
|
|
|
gdal.Unlink(tmpfilename)
|
|
|
|
|
|
###############################################################################
|
|
# Test fix for https://github.com/OSGeo/gdal/issues/7319
|
|
|
|
|
|
def test_ogr_geojson_coordinate_precision():
|
|
|
|
filename = "/vsimem/test_ogr_geojson_coordinate_precision.json"
|
|
ds = ogr.GetDriverByName("GeoJSON").CreateDataSource(filename)
|
|
lyr = ds.CreateLayer("foo", options=["COORDINATE_PRECISION=1", "WRITE_BBOX=YES"])
|
|
|
|
f = ogr.Feature(lyr.GetLayerDefn())
|
|
f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1.23456789 2.3456789)"))
|
|
lyr.CreateFeature(f)
|
|
|
|
ds = None
|
|
|
|
fp = gdal.VSIFOpenL(filename, "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
gdal.Unlink(filename)
|
|
|
|
assert '"bbox": [ 1.2, 2.3, 1.2, 2.3 ]' in data
|
|
assert '"coordinates": [ 1.2, 2.3 ]' in data
|
|
assert "3456" not in data
|
|
|
|
|
|
###############################################################################
|
|
# Test fix for https://github.com/OSGeo/gdal/issues/7319
|
|
|
|
|
|
def test_ogr_geojson_field_types():
|
|
|
|
filename = "/vsimem/test_ogr_geojson_field_types.json"
|
|
|
|
test_data = """{"type":"FeatureCollection","name":"My Collection","features":[
|
|
{ "type": "Feature", "properties": { "prop0": 42 }, "geometry": { "type": "Point", "coordinates": [ 102.0, 0.5 ] } },
|
|
{ "type": "Feature", "properties": { "prop0": "42" }, "geometry": { "type": "Point", "coordinates": [ 102.0, 0.5 ] } },
|
|
{ "type": "Feature", "properties": { "prop0": "astring" }, "geometry": { "type": "Point", "coordinates": [ 102.0, 0.5 ] } },
|
|
{ "type": "Feature", "properties": { "prop0": { "nested": 75 } }, "geometry": { "type": "Point", "coordinates": [ 102.0, 0.5 ] } },
|
|
{ "type": "Feature", "properties": { "prop0": { "a": "b" } }, "geometry": { "type": "Point", "coordinates": [ 102.0, 0.5 ] } }
|
|
]}
|
|
"""
|
|
|
|
srcds = gdal.OpenEx(
|
|
test_data,
|
|
gdal.OF_VECTOR,
|
|
open_options=["NATIVE_DATA=TRUE"],
|
|
)
|
|
|
|
gdal.VectorTranslate(filename, srcds, options="-f GeoJSON -lco NATIVE_DATA=TRUE")
|
|
|
|
fp = gdal.VSIFOpenL(filename, "rb")
|
|
data = gdal.VSIFReadL(1, 10000, fp).decode("ascii")
|
|
gdal.VSIFCloseL(fp)
|
|
|
|
assert '{ "prop0": "42" }' in data
|
|
assert '{ "prop0": "astring" }' in data
|
|
assert '{ "prop0": { "nested": 75 } }' in data
|
|
assert '{ "prop0": 42 }' in data
|
|
assert '{ "prop0": { "a": "b" } }' in data
|
|
|
|
gdal.Unlink(filename)
|
|
|
|
|
|
###############################################################################
|
|
# Test opening with non C locale
|
|
|
|
|
|
def test_ogr_geojson_open_with_non_C_locale():
|
|
|
|
import locale
|
|
|
|
original_locale = locale.setlocale(locale.LC_ALL)
|
|
try:
|
|
locale.setlocale(locale.LC_ALL, "")
|
|
if locale.localeconv()["decimal_point"] == ".":
|
|
pytest.skip("cannot test, as decimal_point is dot")
|
|
|
|
test_ogr_geojson_2()
|
|
finally:
|
|
locale.setlocale(locale.LC_ALL, original_locale)
|