531 lines
20 KiB
Python
531 lines
20 KiB
Python
#!/usr/bin/env python3
|
|
# *****************************************************************************
|
|
# $Id: ogrinfo.py e4fe7cc06270e5f38dfe78e6785a6bcca4e39e29 2021-04-01 21:02:04 +0300 Idan Miara $
|
|
#
|
|
# Project: OpenGIS Simple Features Reference Implementation
|
|
# Purpose: Python port of a simple client for viewing OGR driver data.
|
|
# Author: Even Rouault, <even dot rouault at spatialys.com>
|
|
#
|
|
# Port from ogrinfo.cpp whose author is Frank Warmerdam
|
|
#
|
|
# *****************************************************************************
|
|
# Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
|
|
# Copyright (c) 1999, Frank Warmerdam
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
# copy of this software and associated documentation files (the "Software"),
|
|
# to deal in the Software without restriction, including without limitation
|
|
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
# and/or sell copies of the Software, and to permit persons to whom the
|
|
# Software is furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included
|
|
# in all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
# DEALINGS IN THE SOFTWARE.
|
|
# ***************************************************************************/
|
|
|
|
# Note : this is the most direct port of ogrinfo.cpp possible
|
|
# It could be made much more Python'ish !
|
|
|
|
import sys
|
|
|
|
from osgeo import gdal
|
|
from osgeo import ogr
|
|
|
|
bReadOnly = False
|
|
bVerbose = True
|
|
bSummaryOnly = False
|
|
nFetchFID = ogr.NullFID
|
|
papszOptions = None
|
|
|
|
|
|
def EQUAL(a, b):
|
|
return a.lower() == b.lower()
|
|
|
|
# **********************************************************************
|
|
# main()
|
|
# **********************************************************************
|
|
|
|
|
|
def main(argv=None):
|
|
global bReadOnly
|
|
global bVerbose
|
|
global bSummaryOnly
|
|
global nFetchFID
|
|
global papszOptions
|
|
|
|
version_num = int(gdal.VersionInfo('VERSION_NUM'))
|
|
if version_num < 1800: # because of ogr.GetFieldTypeName
|
|
print('ERROR: Python bindings of GDAL 1.8.0 or later required')
|
|
return 1
|
|
|
|
pszWHERE = None
|
|
pszDataSource = None
|
|
papszLayers = None
|
|
poSpatialFilter = None
|
|
nRepeatCount = 1
|
|
bAllLayers = False
|
|
pszSQLStatement = None
|
|
pszDialect = None
|
|
options = {}
|
|
pszGeomField = None
|
|
|
|
if argv is None:
|
|
argv = sys.argv
|
|
|
|
argv = ogr.GeneralCmdLineProcessor(argv)
|
|
|
|
# --------------------------------------------------------------------
|
|
# Processing command line arguments.
|
|
# --------------------------------------------------------------------
|
|
if argv is None:
|
|
return 1
|
|
|
|
nArgc = len(argv)
|
|
|
|
iArg = 1
|
|
while iArg < nArgc:
|
|
|
|
if EQUAL(argv[iArg], "--utility_version"):
|
|
print("%s is running against GDAL %s" %
|
|
(argv[0], gdal.VersionInfo("RELEASE_NAME")))
|
|
return 0
|
|
|
|
elif EQUAL(argv[iArg], "-ro"):
|
|
bReadOnly = True
|
|
elif EQUAL(argv[iArg], "-q") or EQUAL(argv[iArg], "-quiet"):
|
|
bVerbose = False
|
|
elif EQUAL(argv[iArg], "-fid") and iArg < nArgc - 1:
|
|
iArg = iArg + 1
|
|
nFetchFID = int(argv[iArg])
|
|
elif EQUAL(argv[iArg], "-spat") and iArg + 4 < nArgc:
|
|
oRing = ogr.Geometry(ogr.wkbLinearRing)
|
|
|
|
oRing.AddPoint(float(argv[iArg + 1]), float(argv[iArg + 2]))
|
|
oRing.AddPoint(float(argv[iArg + 1]), float(argv[iArg + 4]))
|
|
oRing.AddPoint(float(argv[iArg + 3]), float(argv[iArg + 4]))
|
|
oRing.AddPoint(float(argv[iArg + 3]), float(argv[iArg + 2]))
|
|
oRing.AddPoint(float(argv[iArg + 1]), float(argv[iArg + 2]))
|
|
|
|
poSpatialFilter = ogr.Geometry(ogr.wkbPolygon)
|
|
poSpatialFilter.AddGeometry(oRing)
|
|
iArg = iArg + 4
|
|
|
|
elif EQUAL(argv[iArg], "-geomfield") and iArg < nArgc - 1:
|
|
iArg = iArg + 1
|
|
pszGeomField = argv[iArg]
|
|
|
|
elif EQUAL(argv[iArg], "-where") and iArg < nArgc - 1:
|
|
iArg = iArg + 1
|
|
pszWHERE = argv[iArg]
|
|
|
|
elif EQUAL(argv[iArg], "-sql") and iArg < nArgc - 1:
|
|
iArg = iArg + 1
|
|
pszSQLStatement = argv[iArg]
|
|
|
|
elif EQUAL(argv[iArg], "-dialect") and iArg < nArgc - 1:
|
|
iArg = iArg + 1
|
|
pszDialect = argv[iArg]
|
|
|
|
elif EQUAL(argv[iArg], "-rc") and iArg < nArgc - 1:
|
|
iArg = iArg + 1
|
|
nRepeatCount = int(argv[iArg])
|
|
|
|
elif EQUAL(argv[iArg], "-al"):
|
|
bAllLayers = True
|
|
|
|
elif EQUAL(argv[iArg], "-so") or EQUAL(argv[iArg], "-summary"):
|
|
bSummaryOnly = True
|
|
|
|
elif len(argv[iArg]) > 8 and EQUAL(argv[iArg][0:8], "-fields="):
|
|
options['DISPLAY_FIELDS'] = argv[iArg][7:len(argv[iArg])]
|
|
|
|
elif len(argv[iArg]) > 6 and EQUAL(argv[iArg][0:6], "-geom="):
|
|
options['DISPLAY_GEOMETRY'] = argv[iArg][6:len(argv[iArg])]
|
|
|
|
elif argv[iArg][0] == '-':
|
|
return Usage()
|
|
|
|
elif pszDataSource is None:
|
|
pszDataSource = argv[iArg]
|
|
else:
|
|
if papszLayers is None:
|
|
papszLayers = []
|
|
papszLayers.append(argv[iArg])
|
|
bAllLayers = False
|
|
|
|
iArg = iArg + 1
|
|
|
|
if pszDataSource is None:
|
|
return Usage()
|
|
|
|
# --------------------------------------------------------------------
|
|
# Open data source.
|
|
# --------------------------------------------------------------------
|
|
poDS = None
|
|
poDriver = None
|
|
|
|
poDS = ogr.Open(pszDataSource, not bReadOnly)
|
|
if poDS is None and not bReadOnly:
|
|
poDS = ogr.Open(pszDataSource, False)
|
|
if poDS is not None and bVerbose:
|
|
print("Had to open data source read-only.")
|
|
bReadOnly = True
|
|
|
|
# --------------------------------------------------------------------
|
|
# Report failure.
|
|
# --------------------------------------------------------------------
|
|
if poDS is None:
|
|
print("FAILURE:\n"
|
|
"Unable to open datasource `%s' with the following drivers." % pszDataSource)
|
|
|
|
for iDriver in range(ogr.GetDriverCount()):
|
|
print(" -> %s" % ogr.GetDriver(iDriver).GetName())
|
|
|
|
return 1
|
|
|
|
poDriver = poDS.GetDriver()
|
|
|
|
# --------------------------------------------------------------------
|
|
# Some information messages.
|
|
# --------------------------------------------------------------------
|
|
if bVerbose:
|
|
print("INFO: Open of `%s'\n"
|
|
" using driver `%s' successful." % (pszDataSource, poDriver.GetName()))
|
|
|
|
poDS_Name = poDS.GetName()
|
|
if str(type(pszDataSource)) == "<type 'unicode'>" and str(type(poDS_Name)) == "<type 'str'>":
|
|
poDS_Name = poDS_Name.decode("utf8")
|
|
if bVerbose and pszDataSource != poDS_Name:
|
|
print("INFO: Internal data source name `%s'\n"
|
|
" different from user name `%s'." % (poDS_Name, pszDataSource))
|
|
|
|
# --------------------------------------------------------------------
|
|
# Special case for -sql clause. No source layers required.
|
|
# --------------------------------------------------------------------
|
|
if pszSQLStatement is not None:
|
|
poResultSet = None
|
|
|
|
nRepeatCount = 0 # // skip layer reporting.
|
|
|
|
if papszLayers is not None:
|
|
print("layer names ignored in combination with -sql.")
|
|
|
|
if pszGeomField is None:
|
|
poResultSet = poDS.ExecuteSQL(pszSQLStatement, poSpatialFilter,
|
|
pszDialect)
|
|
else:
|
|
poResultSet = poDS.ExecuteSQL(pszSQLStatement, None, pszDialect)
|
|
|
|
if poResultSet is not None:
|
|
if pszWHERE is not None:
|
|
if poResultSet.SetAttributeFilter(pszWHERE) != 0:
|
|
print("FAILURE: SetAttributeFilter(%s) failed." % pszWHERE)
|
|
return 1
|
|
|
|
if pszGeomField is not None:
|
|
ReportOnLayer(poResultSet, None, pszGeomField, poSpatialFilter, options)
|
|
else:
|
|
ReportOnLayer(poResultSet, None, None, None, options)
|
|
poDS.ReleaseResultSet(poResultSet)
|
|
|
|
# gdal.Debug( "OGR", "GetLayerCount() = %d\n", poDS.GetLayerCount() )
|
|
|
|
for iRepeat in range(nRepeatCount):
|
|
if papszLayers is None:
|
|
# --------------------------------------------------------------------
|
|
# Process each data source layer.
|
|
# --------------------------------------------------------------------
|
|
for iLayer in range(poDS.GetLayerCount()):
|
|
poLayer = poDS.GetLayer(iLayer)
|
|
|
|
if poLayer is None:
|
|
print("FAILURE: Couldn't fetch advertised layer %d!" % iLayer)
|
|
return 1
|
|
|
|
if not bAllLayers:
|
|
line = "%d: %s" % (iLayer + 1, poLayer.GetLayerDefn().GetName())
|
|
|
|
nGeomFieldCount = poLayer.GetLayerDefn().GetGeomFieldCount()
|
|
if nGeomFieldCount > 1:
|
|
line = line + " ("
|
|
for iGeom in range(nGeomFieldCount):
|
|
if iGeom > 0:
|
|
line = line + ", "
|
|
poGFldDefn = poLayer.GetLayerDefn().GetGeomFieldDefn(iGeom)
|
|
line = line + "%s" % ogr.GeometryTypeToName(poGFldDefn.GetType())
|
|
line = line + ")"
|
|
|
|
if poLayer.GetLayerDefn().GetGeomType() != ogr.wkbUnknown:
|
|
line = line + " (%s)" % ogr.GeometryTypeToName(poLayer.GetLayerDefn().GetGeomType())
|
|
|
|
print(line)
|
|
else:
|
|
if iRepeat != 0:
|
|
poLayer.ResetReading()
|
|
|
|
ReportOnLayer(poLayer, pszWHERE, pszGeomField, poSpatialFilter, options)
|
|
|
|
else:
|
|
# --------------------------------------------------------------------
|
|
# Process specified data source layers.
|
|
# --------------------------------------------------------------------
|
|
for papszIter in papszLayers:
|
|
poLayer = poDS.GetLayerByName(papszIter)
|
|
|
|
if poLayer is None:
|
|
print("FAILURE: Couldn't fetch requested layer %s!" % papszIter)
|
|
return 1
|
|
|
|
if iRepeat != 0:
|
|
poLayer.ResetReading()
|
|
|
|
ReportOnLayer(poLayer, pszWHERE, pszGeomField, poSpatialFilter, options)
|
|
|
|
# --------------------------------------------------------------------
|
|
# Close down.
|
|
# --------------------------------------------------------------------
|
|
poDS.Destroy()
|
|
|
|
return 0
|
|
|
|
# **********************************************************************
|
|
# Usage()
|
|
# **********************************************************************
|
|
|
|
|
|
def Usage():
|
|
print("Usage: ogrinfo [--help-general] [-ro] [-q] [-where restricted_where]\n"
|
|
" [-spat xmin ymin xmax ymax] [-geomfield field] [-fid fid]\n"
|
|
" [-sql statement] [-al] [-so] [-fields={YES/NO}]\n"
|
|
" [-geom={YES/NO/SUMMARY}][--formats]\n"
|
|
" datasource_name [layer [layer ...]]")
|
|
return 1
|
|
|
|
# **********************************************************************
|
|
# ReportOnLayer()
|
|
# **********************************************************************
|
|
|
|
|
|
def ReportOnLayer(poLayer, pszWHERE, pszGeomField, poSpatialFilter, options):
|
|
|
|
poDefn = poLayer.GetLayerDefn()
|
|
|
|
# --------------------------------------------------------------------
|
|
# Set filters if provided.
|
|
# --------------------------------------------------------------------
|
|
if pszWHERE is not None:
|
|
if poLayer.SetAttributeFilter(pszWHERE) != 0:
|
|
print("FAILURE: SetAttributeFilter(%s) failed." % pszWHERE)
|
|
return
|
|
|
|
if poSpatialFilter is not None:
|
|
if pszGeomField is not None:
|
|
iGeomField = poLayer.GetLayerDefn().GetGeomFieldIndex(pszGeomField)
|
|
if iGeomField >= 0:
|
|
poLayer.SetSpatialFilter(iGeomField, poSpatialFilter)
|
|
else:
|
|
print("WARNING: Cannot find geometry field %s." % pszGeomField)
|
|
else:
|
|
poLayer.SetSpatialFilter(poSpatialFilter)
|
|
|
|
# --------------------------------------------------------------------
|
|
# Report various overall information.
|
|
# --------------------------------------------------------------------
|
|
print("")
|
|
|
|
print("Layer name: %s" % poDefn.GetName())
|
|
|
|
if bVerbose:
|
|
nGeomFieldCount = poLayer.GetLayerDefn().GetGeomFieldCount()
|
|
if nGeomFieldCount > 1:
|
|
for iGeom in range(nGeomFieldCount):
|
|
poGFldDefn = poLayer.GetLayerDefn().GetGeomFieldDefn(iGeom)
|
|
print("Geometry (%s): %s" % (poGFldDefn.GetNameRef(), ogr.GeometryTypeToName(poGFldDefn.GetType())))
|
|
else:
|
|
print("Geometry: %s" % ogr.GeometryTypeToName(poDefn.GetGeomType()))
|
|
|
|
print("Feature Count: %d" % poLayer.GetFeatureCount())
|
|
|
|
if nGeomFieldCount > 1:
|
|
for iGeom in range(nGeomFieldCount):
|
|
poGFldDefn = poLayer.GetLayerDefn().GetGeomFieldDefn(iGeom)
|
|
oExt = poLayer.GetExtent(True, geom_field=iGeom, can_return_null=True)
|
|
if oExt is not None:
|
|
print("Extent (%s): (%f, %f) - (%f, %f)" % (poGFldDefn.GetNameRef(), oExt[0], oExt[2], oExt[1], oExt[3]))
|
|
else:
|
|
oExt = poLayer.GetExtent(True, can_return_null=True)
|
|
if oExt is not None:
|
|
print("Extent: (%f, %f) - (%f, %f)" % (oExt[0], oExt[2], oExt[1], oExt[3]))
|
|
|
|
if nGeomFieldCount > 1:
|
|
for iGeom in range(nGeomFieldCount):
|
|
poGFldDefn = poLayer.GetLayerDefn().GetGeomFieldDefn(iGeom)
|
|
if poGFldDefn.GetSpatialRef() is None:
|
|
pszWKT = "(unknown)"
|
|
else:
|
|
pszWKT = poGFldDefn.GetSpatialRef().ExportToPrettyWkt()
|
|
print("SRS WKT (%s):\n%s" % (poGFldDefn.GetNameRef(), pszWKT))
|
|
else:
|
|
if poLayer.GetSpatialRef() is None:
|
|
pszWKT = "(unknown)"
|
|
else:
|
|
pszWKT = poLayer.GetSpatialRef().ExportToPrettyWkt()
|
|
print("Layer SRS WKT:\n%s" % pszWKT)
|
|
|
|
if poLayer.GetFIDColumn():
|
|
print("FID Column = %s" % poLayer.GetFIDColumn())
|
|
|
|
if nGeomFieldCount > 1:
|
|
for iGeom in range(nGeomFieldCount):
|
|
poGFldDefn = poLayer.GetLayerDefn().GetGeomFieldDefn(iGeom)
|
|
print("Geometry Column %d = %s" % (iGeom + 1, poGFldDefn.GetNameRef()))
|
|
else:
|
|
if poLayer.GetGeometryColumn():
|
|
print("Geometry Column = %s" % poLayer.GetGeometryColumn())
|
|
|
|
for iAttr in range(poDefn.GetFieldCount()):
|
|
poField = poDefn.GetFieldDefn(iAttr)
|
|
|
|
print("%s: %s (%d.%d)" % (
|
|
poField.GetNameRef(),
|
|
poField.GetFieldTypeName(poField.GetType()),
|
|
poField.GetWidth(),
|
|
poField.GetPrecision()))
|
|
|
|
# --------------------------------------------------------------------
|
|
# Read, and dump features.
|
|
# --------------------------------------------------------------------
|
|
poFeature = None
|
|
|
|
if nFetchFID == ogr.NullFID and not bSummaryOnly:
|
|
|
|
poFeature = poLayer.GetNextFeature()
|
|
while poFeature is not None:
|
|
DumpReadableFeature(poFeature, options)
|
|
poFeature = poLayer.GetNextFeature()
|
|
|
|
elif nFetchFID != ogr.NullFID:
|
|
|
|
poFeature = poLayer.GetFeature(nFetchFID)
|
|
if poFeature is None:
|
|
print("Unable to locate feature id %d on this layer." % nFetchFID)
|
|
|
|
else:
|
|
DumpReadableFeature(poFeature, options)
|
|
|
|
return
|
|
|
|
|
|
def DumpReadableFeature(poFeature, options=None):
|
|
|
|
poDefn = poFeature.GetDefnRef()
|
|
print("OGRFeature(%s):%ld" % (poDefn.GetName(), poFeature.GetFID()))
|
|
|
|
if 'DISPLAY_FIELDS' not in options or EQUAL(options['DISPLAY_FIELDS'], 'yes'):
|
|
for iField in range(poDefn.GetFieldCount()):
|
|
|
|
poFDefn = poDefn.GetFieldDefn(iField)
|
|
|
|
line = " %s (%s) = " % (
|
|
poFDefn.GetNameRef(),
|
|
ogr.GetFieldTypeName(poFDefn.GetType()))
|
|
|
|
if poFeature.IsFieldSet(iField):
|
|
try:
|
|
line = line + "%s" % (poFeature.GetFieldAsString(iField))
|
|
except:
|
|
# For Python3 on non-UTF8 strings
|
|
line = line + "%s" % (poFeature.GetFieldAsBinary(iField))
|
|
else:
|
|
line = line + "(null)"
|
|
|
|
print(line)
|
|
|
|
if poFeature.GetStyleString() is not None:
|
|
|
|
if 'DISPLAY_STYLE' not in options or EQUAL(options['DISPLAY_STYLE'], 'yes'):
|
|
print(" Style = %s" % poFeature.GetStyleString())
|
|
|
|
nGeomFieldCount = poFeature.GetGeomFieldCount()
|
|
if nGeomFieldCount > 0:
|
|
if 'DISPLAY_GEOMETRY' not in options or not EQUAL(options['DISPLAY_GEOMETRY'], 'no'):
|
|
for iField in range(nGeomFieldCount):
|
|
poGFldDefn = poFeature.GetDefnRef().GetGeomFieldDefn(iField)
|
|
poGeometry = poFeature.GetGeomFieldRef(iField)
|
|
if poGeometry is not None:
|
|
sys.stdout.write(" ")
|
|
if poGFldDefn.GetNameRef() and nGeomFieldCount > 1:
|
|
sys.stdout.write("%s = " % poGFldDefn.GetNameRef())
|
|
DumpReadableGeometry(poGeometry, "", options)
|
|
|
|
print('')
|
|
|
|
|
|
def DumpReadableGeometry(poGeometry, pszPrefix, options):
|
|
|
|
if pszPrefix is None:
|
|
pszPrefix = ""
|
|
|
|
if 'DISPLAY_GEOMETRY' in options and EQUAL(options['DISPLAY_GEOMETRY'], 'SUMMARY'):
|
|
|
|
line = ("%s%s : " % (pszPrefix, poGeometry.GetGeometryName()))
|
|
eType = poGeometry.GetGeometryType()
|
|
if eType == ogr.wkbLineString or eType == ogr.wkbLineString25D:
|
|
line = line + ("%d points" % poGeometry.GetPointCount())
|
|
print(line)
|
|
elif eType == ogr.wkbPolygon or eType == ogr.wkbPolygon25D:
|
|
nRings = poGeometry.GetGeometryCount()
|
|
if nRings == 0:
|
|
line = line + "empty"
|
|
else:
|
|
poRing = poGeometry.GetGeometryRef(0)
|
|
line = line + ("%d points" % poRing.GetPointCount())
|
|
if nRings > 1:
|
|
line = line + (", %d inner rings (" % (nRings - 1))
|
|
for ir in range(0, nRings - 1):
|
|
if ir > 0:
|
|
line = line + ", "
|
|
poRing = poGeometry.GetGeometryRef(ir + 1)
|
|
line = line + ("%d points" % poRing.GetPointCount())
|
|
line = line + ")"
|
|
print(line)
|
|
|
|
elif eType == ogr.wkbMultiPoint or \
|
|
eType == ogr.wkbMultiPoint25D or \
|
|
eType == ogr.wkbMultiLineString or \
|
|
eType == ogr.wkbMultiLineString25D or \
|
|
eType == ogr.wkbMultiPolygon or \
|
|
eType == ogr.wkbMultiPolygon25D or \
|
|
eType == ogr.wkbGeometryCollection or \
|
|
eType == ogr.wkbGeometryCollection25D:
|
|
|
|
line = line + "%d geometries:" % poGeometry.GetGeometryCount()
|
|
print(line)
|
|
for ig in range(poGeometry.GetGeometryCount()):
|
|
subgeom = poGeometry.GetGeometryRef(ig)
|
|
from sys import version_info
|
|
if version_info >= (3, 0, 0):
|
|
exec('print("", end=" ")')
|
|
else:
|
|
exec('print "", ')
|
|
DumpReadableGeometry(subgeom, pszPrefix, options)
|
|
else:
|
|
print(line)
|
|
|
|
elif 'DISPLAY_GEOMETRY' not in options or EQUAL(options['DISPLAY_GEOMETRY'], 'yes') \
|
|
or EQUAL(options['DISPLAY_GEOMETRY'], 'WKT'):
|
|
|
|
print("%s%s" % (pszPrefix, poGeometry.ExportToWkt()))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main(sys.argv))
|