Skip to content

Commit

Permalink
ogrinfo: add a -extent3D switch
Browse files Browse the repository at this point in the history
  • Loading branch information
rouault committed Dec 6, 2023
1 parent 2e18f32 commit fcd2474
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 26 deletions.
5 changes: 3 additions & 2 deletions apps/ogrinfo_bin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@ static void Usage(bool bIsError, const char *pszErrorMsg = nullptr)
" [-geom={YES|NO|SUMMARY|WKT|ISO_WKT}] "
"[-oo <NAME>=<VALUE>]...\n"
" [-nomd] [-listmdd] [-mdd {<domain>|all}]...\n"
" [-nocount] [-noextent] [-nogeomtype] [-wkt_format "
"WKT1|WKT2|<other_values>]\n"
" [-nocount] [-nogeomtype] "
"[[-noextent] | [-extent3D]]\n"
" [-wkt_format WKT1|WKT2|<other_values>]\n"
" [-fielddomain <name>]\n"
" <datasource_name> [<layer> [<layer> ...]]\n");

Expand Down
127 changes: 106 additions & 21 deletions apps/ogrinfo_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ struct GDALVectorInfoOptions
bool bShowMetadata = true;
bool bFeatureCount = true;
bool bExtent = true;
bool bExtent3D = false;
bool bGeomType = true;
bool bDatasetGetNextFeature = false;
bool bVerbose = true;
Expand Down Expand Up @@ -880,7 +881,6 @@ static void ReportOnLayer(CPLString &osRet, CPLJSONObject oLayer,
const char *const apszWKTOptions[] = {osWKTFormat.c_str(),
"MULTILINE=YES", nullptr};

OGREnvelope oExt;
if (bJson || nGeomFieldCount > 1)
{
CPLJSONArray oGeometryFields;
Expand All @@ -902,15 +902,51 @@ static void ReportOnLayer(CPLString &osRet, CPLJSONObject oLayer,
/*bSpaceBeforeZM=*/false));
oGeometryField.Set("nullable",
CPL_TO_BOOL(poGFldDefn->IsNullable()));
if (psOptions->bExtent &&
poLayer->GetExtent(iGeom, &oExt, TRUE) == OGRERR_NONE)
if (psOptions->bExtent3D)
{
CPLJSONArray oBbox;
oBbox.Add(oExt.MinX);
oBbox.Add(oExt.MinY);
oBbox.Add(oExt.MaxX);
oBbox.Add(oExt.MaxY);
oGeometryField.Add("extent", oBbox);
OGREnvelope3D oExt;
if (poLayer->GetExtent3D(iGeom, &oExt, TRUE) ==
OGRERR_NONE)
{
{
CPLJSONArray oBbox;
oBbox.Add(oExt.MinX);
oBbox.Add(oExt.MinY);
oBbox.Add(oExt.MaxX);
oBbox.Add(oExt.MaxY);
oGeometryField.Add("extent", oBbox);
}
{
CPLJSONArray oBbox;
oBbox.Add(oExt.MinX);
oBbox.Add(oExt.MinY);
if (std::isfinite(oExt.MinZ))
oBbox.Add(oExt.MinZ);
else
oBbox.AddNull();
oBbox.Add(oExt.MaxX);
oBbox.Add(oExt.MaxY);
if (std::isfinite(oExt.MaxZ))
oBbox.Add(oExt.MaxZ);
else
oBbox.AddNull();
oGeometryField.Add("extent3D", oBbox);
}
}
}
else if (psOptions->bExtent)
{
OGREnvelope oExt;
if (poLayer->GetExtent(iGeom, &oExt, TRUE) ==
OGRERR_NONE)
{
CPLJSONArray oBbox;
oBbox.Add(oExt.MinX);
oBbox.Add(oExt.MinY);
oBbox.Add(oExt.MaxX);
oBbox.Add(oExt.MaxY);
oGeometryField.Add("extent", oBbox);
}
}
const OGRSpatialReference *poSRS =
poGFldDefn->GetSpatialRef();
Expand Down Expand Up @@ -1029,23 +1065,68 @@ static void ReportOnLayer(CPLString &osRet, CPLJSONObject oLayer,
{
for (int iGeom = 0; iGeom < nGeomFieldCount; iGeom++)
{
if (poLayer->GetExtent(iGeom, &oExt, TRUE) == OGRERR_NONE)
if (psOptions->bExtent3D)
{
OGRGeomFieldDefn *poGFldDefn =
poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
Concat(osRet, psOptions->bStdoutOutput,
"Extent (%s): (%f, %f) - (%f, %f)\n",
poGFldDefn->GetNameRef(), oExt.MinX, oExt.MinY,
oExt.MaxX, oExt.MaxY);
OGREnvelope3D oExt;
if (poLayer->GetExtent3D(iGeom, &oExt, TRUE) == OGRERR_NONE)
{
OGRGeomFieldDefn *poGFldDefn =
poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
Concat(osRet, psOptions->bStdoutOutput,
"Extent (%s): (%f, %f, %s) - (%f, %f, %s)\n",
poGFldDefn->GetNameRef(), oExt.MinX, oExt.MinY,
std::isfinite(oExt.MinZ)
? CPLSPrintf("%f", oExt.MinZ)
: "none",
oExt.MaxX, oExt.MaxY,
std::isfinite(oExt.MaxZ)
? CPLSPrintf("%f", oExt.MaxZ)
: "none");
}
}
else
{
OGREnvelope oExt;
if (poLayer->GetExtent(iGeom, &oExt, TRUE) == OGRERR_NONE)
{
OGRGeomFieldDefn *poGFldDefn =
poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
Concat(osRet, psOptions->bStdoutOutput,
"Extent (%s): (%f, %f) - (%f, %f)\n",
poGFldDefn->GetNameRef(), oExt.MinX, oExt.MinY,
oExt.MaxX, oExt.MaxY);
}
}
}
}
else if (!bJson && psOptions->bExtent &&
poLayer->GetExtent(&oExt, TRUE) == OGRERR_NONE)
else if (!bJson && psOptions->bExtent)
{
Concat(osRet, psOptions->bStdoutOutput,
"Extent: (%f, %f) - (%f, %f)\n", oExt.MinX, oExt.MinY,
oExt.MaxX, oExt.MaxY);
if (psOptions->bExtent3D)
{
OGREnvelope3D oExt;
if (poLayer->GetExtent3D(0, &oExt, TRUE) == OGRERR_NONE)
{
Concat(
osRet, psOptions->bStdoutOutput,
"Extent: (%f, %f, %s) - (%f, %f, %s)\n", oExt.MinX,
oExt.MinY,
std::isfinite(oExt.MinZ) ? CPLSPrintf("%f", oExt.MinZ)
: "none",
oExt.MaxX, oExt.MaxY,
std::isfinite(oExt.MaxZ) ? CPLSPrintf("%f", oExt.MaxZ)
: "none");
}
}
else
{
OGREnvelope oExt;
if (poLayer->GetExtent(&oExt, TRUE) == OGRERR_NONE)
{
Concat(osRet, psOptions->bStdoutOutput,
"Extent: (%f, %f) - (%f, %f)\n", oExt.MinX,
oExt.MinY, oExt.MaxX, oExt.MaxY);
}
}
}

const auto displayExtraInfoSRS =
Expand Down Expand Up @@ -2208,6 +2289,10 @@ GDALVectorInfoOptionsNew(char **papszArgv,
{
psOptions->bExtent = false;
}
else if (EQUAL(papszArgv[iArg], "-extent3D"))
{
psOptions->bExtent3D = true;
}
else if (EQUAL(papszArgv[iArg], "-nogeomtype"))
{
psOptions->bGeomType = false;
Expand Down
63 changes: 63 additions & 0 deletions autotest/utilities/test_ogrinfo_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -879,3 +879,66 @@ def test_ogrinfo_lib_time_zones():
assert fields[3]["timezone"] == "UTC"
assert fields[4]["timezone"] == "+01:00"
assert fields[5]["timezone"] == "-01:00"


###############################################################################
# Test -extent3D


@pytest.mark.require_driver("ESRI Shapefile")
@pytest.mark.require_driver("GPKG")
def test_ogrinfo_lib_extent3D():

ret = gdal.VectorInfo("../ogr/data/poly.shp", extent="3D")
assert (
"(478315.531250, 4762880.500000, none) - (481645.312500, 4765610.500000, none)"
in ret
)

ret = gdal.VectorInfo("../ogr/data/poly.shp", extent="3D", format="json")
assert ret["layers"][0]["geometryFields"][0]["extent"] == [
478315.53125,
4762880.5,
481645.3125,
4765610.5,
]
assert ret["layers"][0]["geometryFields"][0]["extent3D"] == [
478315.53125,
4762880.5,
None,
481645.3125,
4765610.5,
None,
]

gdaltest.validate_json(ret, "ogrinfo_output.schema.json")

ret = gdal.VectorInfo("../ogr/data/gpkg/3d_envelope.gpkg", extent="3D")
assert "(0.000000, 0.000000, 0.000000) - (3.000000, 3.000000, 3.000000)" in ret

ret = gdal.VectorInfo(
"../ogr/data/gpkg/3d_envelope.gpkg", extent="3D", format="json"
)
assert ret["layers"][0]["geometryFields"][0]["extent"] == [0.0, 0.0, 3.0, 3.0]
assert ret["layers"][0]["geometryFields"][0]["extent3D"] == [
0.0,
0.0,
0.0,
3.0,
3.0,
3.0,
]

gdaltest.validate_json(ret, "ogrinfo_output.schema.json")

ret = gdal.VectorInfo(
"../ogr/data/gpkg/3d_envelope.gpkg", extent="3D", where="fid = 1", format="json"
)
assert ret["layers"][0]["geometryFields"][0]["extent3D"] == [
0.0,
0.0,
0.0,
1.0,
1.0,
1.0,
]
11 changes: 11 additions & 0 deletions data/ogrinfo_output.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,17 @@
"maxItems": 4
}
},
"extent3D": {
"type": "array",
"items": {
"type": [
"null",
"number"
],
"minItems": 6,
"maxItems": 6
}
},
"coordinateSystem": {
"oneOf": [
{
Expand Down
11 changes: 10 additions & 1 deletion doc/source/programs/ogrinfo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ Synopsis
[-so|-features] [-fields={YES|NO}]]
[-geom={YES|NO|SUMMARY|WKT|ISO_WKT}] [-oo <NAME>=<VALUE>]...
[-nomd] [-listmdd] [-mdd <domain>|all]...
[-nocount] [-noextent] [-nogeomtype] [-wkt_format WKT1|WKT2|<other_values>]
[-nocount] [-nogeomtype] [[-noextent] | [-extent3D]]
[-wkt_format WKT1|WKT2|<other_values>]
[-fielddomain <name>]
<datasource_name> [<layer> [<layer> ...]]
Expand Down Expand Up @@ -173,6 +174,14 @@ edit data.

Suppress spatial extent printing.

.. option:: -extent3D

.. versionadded:: 3.9

Request a 3D extent to be reported (the default is 2D only). Note that this
operation might be slower than requesting the 2D extent, depending on format
and driver capabilities.

.. option:: -nogeomtype

Suppress layer geometry type printing.
Expand Down
6 changes: 4 additions & 2 deletions swig/include/python/gdal_python.i
Original file line number Diff line number Diff line change
Expand Up @@ -1733,7 +1733,7 @@ def VectorInfoOptions(options=None,
featureCount:
whether to compute and display the feature count
extent:
whether to compute and display the layer extent
whether to compute and display the layer extent. Can also be set to the string '3D' to request a 3D extent
dumpFeatures:
set to True to get the dump of all features
"""
Expand Down Expand Up @@ -1764,7 +1764,9 @@ def VectorInfoOptions(options=None,
new_options += ['-wkt_format', wktFormat]
if not featureCount:
new_options += ['-nocount']
if not extent:
if extent in ('3d', '3D'):
new_options += ['-extent3D']
elif not extent:
new_options += ['-noextent']
if layers:
new_options += ["dummy_dataset_name"]
Expand Down

0 comments on commit fcd2474

Please sign in to comment.