Skip to content

Commit

Permalink
Retrieve and handle table type (geometryless layers) from ArcGIS
Browse files Browse the repository at this point in the history
rest services
  • Loading branch information
nyalldawson committed May 22, 2023
1 parent f530135 commit 7b42acd
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 71 deletions.
22 changes: 22 additions & 0 deletions src/core/providers/arcgis/qgsarcgisrestquery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,28 @@ void QgsArcGisRestQueryUtils::addLayerItems( const std::function<void ( const QS
}
}

const QVariantList tableInfoList = serviceData.value( QStringLiteral( "tables" ) ).toList();
for ( const QVariant &tableInfo : tableInfoList )
{
const QVariantMap tableInfoMap = tableInfo.toMap();
const QString id = tableInfoMap.value( QStringLiteral( "id" ) ).toString();
const QString parentLayerId = tableInfoMap.value( QStringLiteral( "parentLayerId" ) ).toString();
const QString name = tableInfoMap.value( QStringLiteral( "name" ) ).toString();
const QString description = tableInfoMap.value( QStringLiteral( "description" ) ).toString();

if ( serviceMayHaveQueryCapability && ( filter == ServiceTypeFilter::Vector || filter == ServiceTypeFilter::AllTypes ) )
{
if ( !tableInfoMap.value( QStringLiteral( "subLayerIds" ) ).toList().empty() )
{
visitor( parentLayerId, ServiceTypeFilter::Vector, Qgis::GeometryType::Null, id, name, description, parentUrl + '/' + id, true, QString(), format );
}
else
{
visitor( parentLayerId, ServiceTypeFilter::Vector, Qgis::GeometryType::Null, id, name, description, parentUrl + '/' + id, false, authid, format );
}
}
}

// Add root MapServer as raster layer when multiple layers are listed
if ( filter != ServiceTypeFilter::Vector && layerInfoList.count() > 1 && serviceData.contains( QStringLiteral( "supportedImageFormatTypes" ) ) )
{
Expand Down
151 changes: 81 additions & 70 deletions src/providers/arcgisrest/qgsafsprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ QgsAfsProvider::QgsAfsProvider( const QString &uri, const ProviderOptions &optio
appendError( QgsErrorMessage( tr( "getLayerInfo failed" ), QStringLiteral( "AFSProvider" ) ) );
return;
}
const bool isTable = layerData.value( QStringLiteral( "type" ) ).toString().compare( QLatin1String( "table" ), Qt::CaseInsensitive ) == 0;
mLayerName = layerData[QStringLiteral( "name" )].toString();
mLayerDescription = layerData[QStringLiteral( "description" )].toString();
mCapabilityStrings = layerData[QStringLiteral( "capabilities" )].toString().split( ',' );
Expand Down Expand Up @@ -86,69 +87,72 @@ QgsAfsProvider::QgsAfsProvider( const QString &uri, const ProviderOptions &optio

mServerSupportsCurves = layerData.value( QStringLiteral( "allowTrueCurvesUpdates" ), false ).toBool();

// Set extent
QStringList coords = mSharedData->mDataSource.param( QStringLiteral( "bbox" ) ).split( ',' );
if ( coords.size() == 4 )
if ( !isTable )
{
bool xminOk = false, yminOk = false, xmaxOk = false, ymaxOk = false;
mSharedData->mExtent.setXMinimum( coords[0].toDouble( &xminOk ) );
mSharedData->mExtent.setYMinimum( coords[1].toDouble( &yminOk ) );
mSharedData->mExtent.setXMaximum( coords[2].toDouble( &xmaxOk ) );
mSharedData->mExtent.setYMaximum( coords[3].toDouble( &ymaxOk ) );
if ( !xminOk || !yminOk || !xmaxOk || !ymaxOk )
mSharedData->mExtent = QgsRectangle();
else
mSharedData->mLimitBBox = true;
}
// Set extent
QStringList coords = mSharedData->mDataSource.param( QStringLiteral( "bbox" ) ).split( ',' );
if ( coords.size() == 4 )
{
bool xminOk = false, yminOk = false, xmaxOk = false, ymaxOk = false;
mSharedData->mExtent.setXMinimum( coords[0].toDouble( &xminOk ) );
mSharedData->mExtent.setYMinimum( coords[1].toDouble( &yminOk ) );
mSharedData->mExtent.setXMaximum( coords[2].toDouble( &xmaxOk ) );
mSharedData->mExtent.setYMaximum( coords[3].toDouble( &ymaxOk ) );
if ( !xminOk || !yminOk || !xmaxOk || !ymaxOk )
mSharedData->mExtent = QgsRectangle();
else
mSharedData->mLimitBBox = true;
}

const QVariantMap layerExtentMap = layerData[QStringLiteral( "extent" )].toMap();
bool xminOk = false, yminOk = false, xmaxOk = false, ymaxOk = false;
QgsRectangle originalExtent;
originalExtent.setXMinimum( layerExtentMap[QStringLiteral( "xmin" )].toDouble( &xminOk ) );
originalExtent.setYMinimum( layerExtentMap[QStringLiteral( "ymin" )].toDouble( &yminOk ) );
originalExtent.setXMaximum( layerExtentMap[QStringLiteral( "xmax" )].toDouble( &xmaxOk ) );
originalExtent.setYMaximum( layerExtentMap[QStringLiteral( "ymax" )].toDouble( &ymaxOk ) );
if ( mSharedData->mExtent.isEmpty() && ( !xminOk || !yminOk || !xmaxOk || !ymaxOk ) )
{
appendError( QgsErrorMessage( tr( "Could not retrieve layer extent" ), QStringLiteral( "AFSProvider" ) ) );
return;
}
const QgsCoordinateReferenceSystem extentCrs = QgsArcGisRestUtils::convertSpatialReference( layerExtentMap[QStringLiteral( "spatialReference" )].toMap() );
if ( mSharedData->mExtent.isEmpty() && !extentCrs.isValid() )
{
appendError( QgsErrorMessage( tr( "Could not parse spatial reference" ), QStringLiteral( "AFSProvider" ) ) );
return;
}
const QVariantMap layerExtentMap = layerData[QStringLiteral( "extent" )].toMap();
bool xminOk = false, yminOk = false, xmaxOk = false, ymaxOk = false;
QgsRectangle originalExtent;
originalExtent.setXMinimum( layerExtentMap[QStringLiteral( "xmin" )].toDouble( &xminOk ) );
originalExtent.setYMinimum( layerExtentMap[QStringLiteral( "ymin" )].toDouble( &yminOk ) );
originalExtent.setXMaximum( layerExtentMap[QStringLiteral( "xmax" )].toDouble( &xmaxOk ) );
originalExtent.setYMaximum( layerExtentMap[QStringLiteral( "ymax" )].toDouble( &ymaxOk ) );
if ( mSharedData->mExtent.isEmpty() && ( !xminOk || !yminOk || !xmaxOk || !ymaxOk ) )
{
appendError( QgsErrorMessage( tr( "Could not retrieve layer extent" ), QStringLiteral( "AFSProvider" ) ) );
return;
}
const QgsCoordinateReferenceSystem extentCrs = QgsArcGisRestUtils::convertSpatialReference( layerExtentMap[QStringLiteral( "spatialReference" )].toMap() );
if ( mSharedData->mExtent.isEmpty() && !extentCrs.isValid() )
{
appendError( QgsErrorMessage( tr( "Could not parse spatial reference" ), QStringLiteral( "AFSProvider" ) ) );
return;
}

if ( !mSharedData->mSourceCRS.isValid() )
mSharedData->mSourceCRS = extentCrs;
if ( !mSharedData->mSourceCRS.isValid() )
mSharedData->mSourceCRS = extentCrs;

if ( xminOk && yminOk && xmaxOk && ymaxOk )
{
QgsLayerMetadata::SpatialExtent spatialExtent;
spatialExtent.bounds = QgsBox3d( originalExtent );
spatialExtent.extentCrs = extentCrs;
QgsLayerMetadata::Extent metadataExtent;
metadataExtent.setSpatialExtents( QList< QgsLayerMetadata::SpatialExtent >() << spatialExtent );
mLayerMetadata.setExtent( metadataExtent );
}
if ( extentCrs.isValid() )
{
mLayerMetadata.setCrs( extentCrs );
}

if ( mSharedData->mExtent.isEmpty() )
{
mSharedData->mExtent = originalExtent;
QgsCoordinateTransform ct( extentCrs, mSharedData->mSourceCRS, options.transformContext );
ct.setBallparkTransformsAreAppropriate( true );
try
if ( xminOk && yminOk && xmaxOk && ymaxOk )
{
mSharedData->mExtent = ct.transformBoundingBox( mSharedData->mExtent );
QgsLayerMetadata::SpatialExtent spatialExtent;
spatialExtent.bounds = QgsBox3d( originalExtent );
spatialExtent.extentCrs = extentCrs;
QgsLayerMetadata::Extent metadataExtent;
metadataExtent.setSpatialExtents( QList< QgsLayerMetadata::SpatialExtent >() << spatialExtent );
mLayerMetadata.setExtent( metadataExtent );
}
catch ( QgsCsException & )
if ( extentCrs.isValid() )
{
QgsDebugError( QStringLiteral( "Exception raised while transforming layer extent" ) );
mLayerMetadata.setCrs( extentCrs );
}

if ( mSharedData->mExtent.isEmpty() )
{
mSharedData->mExtent = originalExtent;
QgsCoordinateTransform ct( extentCrs, mSharedData->mSourceCRS, options.transformContext );
ct.setBallparkTransformsAreAppropriate( true );
try
{
mSharedData->mExtent = ct.transformBoundingBox( mSharedData->mExtent );
}
catch ( QgsCsException & )
{
QgsDebugError( QStringLiteral( "Exception raised while transforming layer extent" ) );
}
}
}

Expand Down Expand Up @@ -214,24 +218,31 @@ QgsAfsProvider::QgsAfsProvider( const QString &uri, const ProviderOptions &optio
if ( objectIdFieldName.isEmpty() )
objectIdFieldName = QStringLiteral( "objectid" );

// Determine geometry type
const bool hasM = layerData[QStringLiteral( "hasM" )].toBool();
const bool hasZ = layerData[QStringLiteral( "hasZ" )].toBool();
mSharedData->mGeometryType = QgsArcGisRestUtils::convertGeometryType( layerData[QStringLiteral( "geometryType" )].toString() );
if ( mSharedData->mGeometryType == Qgis::WkbType::Unknown )
if ( isTable )
{
if ( layerData.value( QStringLiteral( "serviceDataType" ) ).toString().startsWith( QLatin1String( "esriImageService" ) ) )
{
// it's possible to connect to ImageServers as a feature service, to view tile boundaries
mSharedData->mGeometryType = Qgis::WkbType::Polygon;
}
else
mSharedData->mGeometryType = Qgis::WkbType::NoGeometry;
}
else
{
// Determine geometry type
const bool hasM = layerData[QStringLiteral( "hasM" )].toBool();
const bool hasZ = layerData[QStringLiteral( "hasZ" )].toBool();
mSharedData->mGeometryType = QgsArcGisRestUtils::convertGeometryType( layerData[QStringLiteral( "geometryType" )].toString() );
if ( mSharedData->mGeometryType == Qgis::WkbType::Unknown )
{
appendError( QgsErrorMessage( tr( "Failed to determine geometry type" ), QStringLiteral( "AFSProvider" ) ) );
return;
if ( layerData.value( QStringLiteral( "serviceDataType" ) ).toString().startsWith( QLatin1String( "esriImageService" ) ) )
{
// it's possible to connect to ImageServers as a feature service, to view tile boundaries
mSharedData->mGeometryType = Qgis::WkbType::Polygon;
}
else
{
appendError( QgsErrorMessage( tr( "Failed to determine geometry type" ), QStringLiteral( "AFSProvider" ) ) );
return;
}
}
mSharedData->mGeometryType = QgsWkbTypes::zmType( mSharedData->mGeometryType, hasZ, hasM );
}
mSharedData->mGeometryType = QgsWkbTypes::zmType( mSharedData->mGeometryType, hasZ, hasM );

// read temporal properties
if ( layerData.contains( QStringLiteral( "timeInfo" ) ) )
Expand Down
3 changes: 2 additions & 1 deletion src/providers/arcgisrest/qgsarcgisrestdataitems.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ void addLayerItems( QVector< QgsDataItem * > &items, const QVariantMap &serviceD
case QgsArcGisRestQueryUtils::ServiceTypeFilter::Vector:
layerItem = std::make_unique< QgsArcGisFeatureServiceLayerItem >( parent, name, url, name, authid, authcfg, headers, geometryType == Qgis::GeometryType::Polygon ? Qgis::BrowserLayerType::Polygon :
geometryType == Qgis::GeometryType::Line ? Qgis::BrowserLayerType::Line
: geometryType == Qgis::GeometryType::Point ? Qgis::BrowserLayerType::Point : Qgis::BrowserLayerType::Vector );
: geometryType == Qgis::GeometryType::Point ? Qgis::BrowserLayerType::Point :
geometryType == Qgis::GeometryType::Null ? Qgis::BrowserLayerType::TableLayer : Qgis::BrowserLayerType::Vector );
break;

case QgsArcGisRestQueryUtils::ServiceTypeFilter::Raster:
Expand Down

0 comments on commit 7b42acd

Please sign in to comment.