Skip to content

Commit

Permalink
Merge pull request #11813 from rouault/rfc107
Browse files Browse the repository at this point in the history
RFC107 candidate implementation
  • Loading branch information
rouault authored Feb 13, 2025
2 parents 8efdf6f + 75c0382 commit c0e4280
Show file tree
Hide file tree
Showing 141 changed files with 1,618 additions and 2,569 deletions.
19 changes: 19 additions & 0 deletions MIGRATION_GUIDE.TXT
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
MIGRATION GUIDE FROM GDAL 3.10 to GDAL 3.11
-------------------------------------------

- The OGRLayer::GetExtent(OGREnvelope*, int bForce) and
OGRLayer::GetExtent(int iGeomField, OGREnvelope*, int bForce) methods are
no longer virtual methods that are implemented by drivers, and the ``int bForce``
parameter is now a ``bool bForce``.
Drivers may implement the new IGetExtent(int iGeomField, OGREnvelope*,
bool bForce) protected virtual method. The public method checks that the
iGeomField value is in range.
Similarly for OGRLayer::GetExtent3D(int iGeomField, OGREnvelope3D*, int bForce)
which is now a user facing method (with the change that the ``int bForce`` is now a
``bool bForce``). Drivers may implement the new IGetExtent3D(int iGeomField, OGREnvelope3D*,
bool bForce) protected virtual method. The public method checks that the
iGeomField value is in range.

- The OGRLayer::SetSpatialFilter() and SetSpatialFilterRect() methods are
no longer virtual methods that are implemented by drivers. They now return
OGRErr instead of void, `and accept a ``const OGRGeometry*``). Drivers may implement
the new ISetSpatialFilter(int iGeomField, const OGRGeometry*) protected virtual method.
The public methods check that the iGeomField value is in range.

- GDAL drivers may now return raster bands with the new data types
GDT_Float16 or GDT_CFloat16. Code that use the GDAL API must be
ready to react to the new data type, possibly by doing RasterIO()
Expand Down
8 changes: 2 additions & 6 deletions apps/gdalalg_vector_select.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,12 +246,8 @@ class GDALVectorSelectAlgorithmLayer final
return OGRLayer::GetFeatureCount(bForce);
}

OGRErr GetExtent(OGREnvelope *psExtent, int bForce) override
{
return m_oSrcLayer.GetExtent(psExtent, bForce);
}

OGRErr GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce) override
OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
bool bForce) override
{
return m_oSrcLayer.GetExtent(iGeomField, psExtent, bForce);
}
Expand Down
22 changes: 3 additions & 19 deletions apps/ogr2ogr_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -795,26 +795,10 @@ class OGRSplitListFieldLayer : public OGRLayer
return poSrcLayer->GetStyleTable();
}

virtual void SetSpatialFilter(OGRGeometry *poGeom) override
virtual OGRErr ISetSpatialFilter(int iGeom,
const OGRGeometry *poGeom) override
{
poSrcLayer->SetSpatialFilter(poGeom);
}

virtual void SetSpatialFilter(int iGeom, OGRGeometry *poGeom) override
{
poSrcLayer->SetSpatialFilter(iGeom, poGeom);
}

virtual void SetSpatialFilterRect(double dfMinX, double dfMinY,
double dfMaxX, double dfMaxY) override
{
poSrcLayer->SetSpatialFilterRect(dfMinX, dfMinY, dfMaxX, dfMaxY);
}

virtual void SetSpatialFilterRect(int iGeom, double dfMinX, double dfMinY,
double dfMaxX, double dfMaxY) override
{
poSrcLayer->SetSpatialFilterRect(iGeom, dfMinX, dfMinY, dfMaxX, dfMaxY);
return poSrcLayer->SetSpatialFilter(iGeom, poGeom);
}

virtual OGRErr SetAttributeFilter(const char *pszFilter) override
Expand Down
3 changes: 2 additions & 1 deletion autotest/ogr/ogr_geojson.py
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,8 @@ def test_ogr_geojson_23(tmp_vsimem):
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
with gdaltest.disable_exceptions():
assert lyr.GetExtent(geom_field=1, can_return_null=True) is None
lyr = None
ds = None

Expand Down
121 changes: 74 additions & 47 deletions autotest/ogr/ogr_oapif.py
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ def NO_LONGER_USED_test_ogr_oapif_fc_links_next_headers():
###############################################################################


def test_ogr_oapif_spatial_filter():
def test_ogr_oapif_spatial_filter_deprecated_api():

# Deprecated API
handler = webserver.SequentialHandler()
Expand All @@ -568,7 +568,31 @@ def test_ogr_oapif_spatial_filter():
ds = ogr.Open("OAPIF:http://localhost:%d/oapif" % gdaltest.webserver_port)
lyr = ds.GetLayer(0)
assert lyr.TestCapability(ogr.OLCFastGetExtent)
assert lyr.GetExtent() == (-10.0, 15.0, 40.0, 50.0)

handler = webserver.SequentialHandler()
_add_dummy_root_and_api_pages(handler)
handler.add(
"GET",
"/oapif/collections/foo/items?limit=20",
200,
{"Content-Type": "application/geo+json"},
"""{ "type": "FeatureCollection", "features": [
{
"type": "Feature",
"properties": {
"foo": "bar"
}
}
] }""",
)
with webserver.install_http_handler(handler):
assert lyr.GetExtent() == (-10.0, 15.0, 40.0, 50.0)


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


def test_ogr_oapif_spatial_filter():

# Nominal API
handler = webserver.SequentialHandler()
Expand All @@ -591,7 +615,6 @@ def test_ogr_oapif_spatial_filter():
with webserver.install_http_handler(handler):
ds = ogr.Open("OAPIF:http://localhost:%d/oapif" % gdaltest.webserver_port)
lyr = ds.GetLayer(0)
assert lyr.GetExtent() == (-10.0, 15.0, 40.0, 50.0)

handler = webserver.SequentialHandler()
_add_dummy_root_and_api_pages(handler)
Expand All @@ -610,6 +633,7 @@ def test_ogr_oapif_spatial_filter():
] }""",
)
with webserver.install_http_handler(handler):
assert lyr.GetExtent() == (-10.0, 15.0, 40.0, 50.0)
assert lyr.GetLayerDefn().GetFieldCount() == 1

lyr.SetSpatialFilterRect(2, 49, 3, 50)
Expand Down Expand Up @@ -1365,11 +1389,6 @@ def test_ogr_oapif_storage_crs_easting_northing():
with webserver.install_http_handler(handler):
ds = ogr.Open("OAPIF:http://localhost:%d/oapif" % gdaltest.webserver_port)
lyr = ds.GetLayer(0)
minx, maxx, miny, maxy = lyr.GetExtent()
assert (minx, miny, maxx, maxy) == pytest.approx(
(-611288.854779237, 4427761.561734099, 1525592.2813932528, 5620112.89047953),
abs=1e-3,
)

handler = webserver.SequentialHandler()
_add_dummy_root_and_api_pages(handler)
Expand All @@ -1389,10 +1408,16 @@ def test_ogr_oapif_storage_crs_easting_northing():
] }""",
)
with webserver.install_http_handler(handler):
srs = lyr.GetSpatialRef()
assert srs
assert srs.GetAuthorityCode(None) == "32631"
assert lyr.GetLayerDefn().GetFieldCount() == 1
minx, maxx, miny, maxy = lyr.GetExtent()
assert (minx, miny, maxx, maxy) == pytest.approx(
(-611288.854779237, 4427761.561734099, 1525592.2813932528, 5620112.89047953),
abs=1e-3,
)

srs = lyr.GetSpatialRef()
assert srs
assert srs.GetAuthorityCode(None) == "32631"
assert lyr.GetLayerDefn().GetFieldCount() == 1

handler = webserver.SequentialHandler()
handler.add(
Expand Down Expand Up @@ -1467,8 +1492,6 @@ def test_ogr_oapif_storage_crs_latitude_longitude():
with webserver.install_http_handler(handler):
ds = ogr.Open("OAPIF:http://localhost:%d/oapif" % gdaltest.webserver_port)
lyr = ds.GetLayer(0)
minx, maxx, miny, maxy = lyr.GetExtent()
assert (minx, miny, maxx, maxy) == pytest.approx((-10, 40, 15, 50), abs=1e-3)

handler = webserver.SequentialHandler()
_add_dummy_root_and_api_pages(handler)
Expand All @@ -1488,12 +1511,15 @@ def test_ogr_oapif_storage_crs_latitude_longitude():
] }""",
)
with webserver.install_http_handler(handler):
srs = lyr.GetSpatialRef()
assert srs
assert srs.GetAuthorityCode(None) == "4326"
assert srs.GetDataAxisToSRSAxisMapping() == [2, 1]
assert srs.GetCoordinateEpoch() == 2022.5
assert lyr.GetLayerDefn().GetFieldCount() == 1
minx, maxx, miny, maxy = lyr.GetExtent()
assert (minx, miny, maxx, maxy) == pytest.approx((-10, 40, 15, 50), abs=1e-3)

srs = lyr.GetSpatialRef()
assert srs
assert srs.GetAuthorityCode(None) == "4326"
assert srs.GetDataAxisToSRSAxisMapping() == [2, 1]
assert srs.GetCoordinateEpoch() == 2022.5
assert lyr.GetLayerDefn().GetFieldCount() == 1

handler = webserver.SequentialHandler()
# Coordinates must be in lat, lon order in the GeoJSON answer
Expand Down Expand Up @@ -1573,11 +1599,6 @@ def test_ogr_oapif_storage_crs_latitude_longitude_non_compliant_server():
open_options=["SERVER_FEATURE_AXIS_ORDER=GIS_FRIENDLY"],
)
lyr = ds.GetLayer(0)
minx, maxx, miny, maxy = lyr.GetExtent()
assert (minx, miny, maxx, maxy) == pytest.approx((-10, 40, 15, 50), abs=1e-3)

supported_srs_list = lyr.GetSupportedSRSList()
assert supported_srs_list is None

handler = webserver.SequentialHandler()
_add_dummy_root_and_api_pages(handler)
Expand All @@ -1597,12 +1618,18 @@ def test_ogr_oapif_storage_crs_latitude_longitude_non_compliant_server():
] }""",
)
with webserver.install_http_handler(handler):
srs = lyr.GetSpatialRef()
assert srs
assert srs.GetAuthorityCode(None) == "4326"
assert srs.GetDataAxisToSRSAxisMapping() == [2, 1]
assert srs.GetCoordinateEpoch() == 2022.5
assert lyr.GetLayerDefn().GetFieldCount() == 1
minx, maxx, miny, maxy = lyr.GetExtent()
assert (minx, miny, maxx, maxy) == pytest.approx((-10, 40, 15, 50), abs=1e-3)

supported_srs_list = lyr.GetSupportedSRSList()
assert supported_srs_list is None

srs = lyr.GetSpatialRef()
assert srs
assert srs.GetAuthorityCode(None) == "4326"
assert srs.GetDataAxisToSRSAxisMapping() == [2, 1]
assert srs.GetCoordinateEpoch() == 2022.5
assert lyr.GetLayerDefn().GetFieldCount() == 1

handler = webserver.SequentialHandler()
# Coordinates must be in lat, lon order in the GeoJSON answer
Expand Down Expand Up @@ -1665,19 +1692,6 @@ def get_collections_handler():
assert ds
lyr = ds.GetLayer(0)

minx, maxx, miny, maxy = lyr.GetExtent()
assert (minx, miny, maxx, maxy) == pytest.approx(
(-611288.854779237, 4427761.561734099, 1525592.2813932528, 5620112.89047953),
abs=1e-3,
)

supported_srs_list = lyr.GetSupportedSRSList()
assert supported_srs_list
assert len(supported_srs_list) == 2
assert supported_srs_list[0].GetAuthorityCode(None) == "32631"
# Below doesn't work with early PROJ 6 versions
# assert supported_srs_list[1].GetAuthorityCode(None) == "CRS84"

def get_items_handler():
handler = webserver.SequentialHandler()
_add_dummy_root_and_api_pages(handler)
Expand All @@ -1699,9 +1713,22 @@ def get_items_handler():
return handler

with webserver.install_http_handler(get_items_handler()):
srs = lyr.GetSpatialRef()
assert srs
assert srs.GetAuthorityCode(None) == "32631"
minx, maxx, miny, maxy = lyr.GetExtent()
assert (minx, miny, maxx, maxy) == pytest.approx(
(-611288.854779237, 4427761.561734099, 1525592.2813932528, 5620112.89047953),
abs=1e-3,
)

supported_srs_list = lyr.GetSupportedSRSList()
assert supported_srs_list
assert len(supported_srs_list) == 2
assert supported_srs_list[0].GetAuthorityCode(None) == "32631"
# Below doesn't work with early PROJ 6 versions
# assert supported_srs_list[1].GetAuthorityCode(None) == "CRS84"

srs = lyr.GetSpatialRef()
assert srs
assert srs.GetAuthorityCode(None) == "32631"

json_info = gdal.VectorInfo(ds, format="json", featureCount=False)
assert "supportedSRSList" in json_info["layers"][0]["geometryFields"][0]
Expand Down
4 changes: 2 additions & 2 deletions autotest/ogr/ogr_sql_sqlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -2473,7 +2473,7 @@ def test_ogr_sql_sqlite_execute_sql_error_on_spatial_filter_mem_layer():
ds.CreateLayer("test")
geom = ogr.CreateGeometryFromWkt("POLYGON((0 0,0 1,1 1,1 0,0 0))")
with pytest.raises(
Exception, match="Cannot set spatial filter: no geometry field selected"
Exception, match="Cannot set spatial filter: no geometry field present in layer"
):
ds.ExecuteSQL("SELECT 1 FROM test", spatialFilter=geom, dialect="SQLITE")

Expand All @@ -2490,6 +2490,6 @@ def test_ogr_sql_sqlite_execute_sql_error_on_spatial_filter_shp_layer(tmp_vsimem
ds.CreateLayer("test")
geom = ogr.CreateGeometryFromWkt("POLYGON((0 0,0 1,1 1,1 0,0 0))")
with pytest.raises(
Exception, match="Cannot set spatial filter: no geometry field selected"
Exception, match="Cannot set spatial filter: no geometry field present in layer"
):
ds.ExecuteSQL("SELECT 1 FROM test", spatialFilter=geom, dialect="SQLITE")
4 changes: 2 additions & 2 deletions autotest/ogr/ogr_vrt.py
Original file line number Diff line number Diff line change
Expand Up @@ -2381,9 +2381,9 @@ def test_ogr_vrt_33b(ogr_vrt_33, tmp_path):
ret = gdaltest.runexternal(
test_cli_utilities.get_test_ogrsf_path() + f" -ro {tmp_path}/ogr_vrt_33.vrt"
)
os.unlink(tmp_path / "ogr_vrt_33.vrt")

assert ret.find("INFO") != -1 and ret.find("ERROR") == -1
assert "INFO" in ret
assert "ERROR" not in ret


@pytest.mark.require_driver("CSV")
Expand Down
27 changes: 10 additions & 17 deletions frmts/eeda/eedadataset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,23 +140,13 @@ class GDALEEDALayer final : public OGRLayer
return -1;
}

virtual void SetSpatialFilter(OGRGeometry *poGeom) CPL_OVERRIDE;

virtual void SetSpatialFilter(int iGeomField,
OGRGeometry *poGeom) CPL_OVERRIDE
{
OGRLayer::SetSpatialFilter(iGeomField, poGeom);
}
virtual OGRErr ISetSpatialFilter(int iGeomField,
const OGRGeometry *poGeom) override;

virtual OGRErr SetAttributeFilter(const char *) CPL_OVERRIDE;

virtual OGRErr GetExtent(OGREnvelope *psExtent, int bForce) CPL_OVERRIDE;

virtual OGRErr GetExtent(int iGeomField, OGREnvelope *psExtent,
int bForce) CPL_OVERRIDE
{
return OGRLayer::GetExtent(iGeomField, psExtent, bForce);
}
virtual OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
bool bForce) override;
};

/************************************************************************/
Expand Down Expand Up @@ -943,10 +933,11 @@ OGRErr GDALEEDALayer::SetAttributeFilter(const char *pszQuery)
}

/************************************************************************/
/* SetSpatialFilter() */
/* ISetSpatialFilter() */
/************************************************************************/

void GDALEEDALayer::SetSpatialFilter(OGRGeometry *poGeomIn)
OGRErr GDALEEDALayer::ISetSpatialFilter(int /* iGeomField */,
const OGRGeometry *poGeomIn)
{
if (poGeomIn)
{
Expand All @@ -965,13 +956,15 @@ void GDALEEDALayer::SetSpatialFilter(OGRGeometry *poGeomIn)
InstallFilter(poGeomIn);

ResetReading();
return OGRERR_NONE;
}

/************************************************************************/
/* GetExtent() */
/************************************************************************/

OGRErr GDALEEDALayer::GetExtent(OGREnvelope *psExtent, int /* bForce */)
OGRErr GDALEEDALayer::IGetExtent(int /* iGeomField*/, OGREnvelope *psExtent,
bool /* bForce */)
{
psExtent->MinX = -180;
psExtent->MinY = -90;
Expand Down
Loading

0 comments on commit c0e4280

Please sign in to comment.