Skip to content

Commit f32cd21

Browse files
committed
Add feature bounding box if called with filter and without I/J
1 parent 57c4ee7 commit f32cd21

File tree

2 files changed

+141
-86
lines changed

2 files changed

+141
-86
lines changed

src/mapserver/qgswmsserver.cpp

Lines changed: 133 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -121,21 +121,21 @@ QDomDocument QgsWMSServer::getCapabilities()
121121

122122
QList<QPair<QString, QString> > queryItems = mapUrl.queryItems();
123123
QList<QPair<QString, QString> >::const_iterator queryIt = queryItems.constBegin();
124-
for(; queryIt != queryItems.constEnd(); ++queryIt )
124+
for ( ; queryIt != queryItems.constEnd(); ++queryIt )
125125
{
126-
if( queryIt->first.compare("REQUEST", Qt::CaseInsensitive ) == 0 )
126+
if ( queryIt->first.compare( "REQUEST", Qt::CaseInsensitive ) == 0 )
127127
{
128128
mapUrl.removeQueryItem( queryIt->first );
129129
}
130-
else if( queryIt->first.compare("VERSION", Qt::CaseInsensitive ) == 0 )
130+
else if ( queryIt->first.compare( "VERSION", Qt::CaseInsensitive ) == 0 )
131131
{
132132
mapUrl.removeQueryItem( queryIt->first );
133133
}
134-
else if( queryIt->first.compare("SERVICE", Qt::CaseInsensitive ) == 0 )
134+
else if ( queryIt->first.compare( "SERVICE", Qt::CaseInsensitive ) == 0 )
135135
{
136136
mapUrl.removeQueryItem( queryIt->first );
137137
}
138-
else if( queryIt->first.compare("_DC", Qt::CaseInsensitive ) == 0 )
138+
else if ( queryIt->first.compare( "_DC", Qt::CaseInsensitive ) == 0 )
139139
{
140140
mapUrl.removeQueryItem( queryIt->first );
141141
}
@@ -636,11 +636,10 @@ int QgsWMSServer::getFeatureInfo( QDomDocument& result )
636636
if ( i_it == mParameterMap.end() )
637637
{
638638
std::map<QString, QString>::const_iterator x_it = mParameterMap.find( "X" );
639-
if ( x_it == mParameterMap.end() )
639+
if ( x_it != mParameterMap.end() )
640640
{
641-
return 5;
641+
iString = x_it->second;
642642
}
643-
iString = x_it->second;
644643
}
645644
else
646645
{
@@ -649,18 +648,17 @@ int QgsWMSServer::getFeatureInfo( QDomDocument& result )
649648
i = iString.toInt( &conversionSuccess );
650649
if ( !conversionSuccess )
651650
{
652-
return 6;
651+
i = -1;
653652
}
654653

655654
std::map<QString, QString>::const_iterator j_it = mParameterMap.find( "J" );
656655
if ( j_it == mParameterMap.end() )
657656
{
658657
std::map<QString, QString>::const_iterator y_it = mParameterMap.find( "Y" );
659-
if ( y_it == mParameterMap.end() )
658+
if ( y_it != mParameterMap.end() )
660659
{
661-
return 7;
660+
jString = y_it->second;
662661
}
663-
jString = y_it->second;
664662
}
665663
else
666664
{
@@ -669,9 +667,34 @@ int QgsWMSServer::getFeatureInfo( QDomDocument& result )
669667
j = jString.toInt( &conversionSuccess );
670668
if ( !conversionSuccess )
671669
{
672-
return 8;
670+
j = -1;
671+
}
672+
673+
//Normally, I/J or X/Y are mandatory parameters.
674+
//However, in order to make attribute only queries via the FILTER parameter, it is allowed to skip them if the FILTER parameter is there
675+
676+
QgsRectangle* featuresRect = 0;
677+
QgsPoint* infoPoint = 0;
678+
if ( i == -1 || j == -1 )
679+
{
680+
if ( mParameterMap.find( "FILTER" ) != mParameterMap.end() )
681+
{
682+
featuresRect = new QgsRectangle();
683+
}
684+
else
685+
{
686+
throw QgsMapServiceException( "ParameterMissing", "I/J parameters are required for GetFeatureInfo" );
687+
}
688+
}
689+
else
690+
{
691+
infoPoint = new QgsPoint();
673692
}
674693

694+
//get the layer registered in QgsMapLayerRegistry and apply possible filters
695+
QStringList layerIds = layerSet( layersList, stylesList, mMapRenderer->destinationCrs() );
696+
QMap<QString, QString> originalLayerFilters = applyRequestedLayerFilters( layersList, layerIds );
697+
675698
QDomElement getFeatureInfoElement = result.createElement( "GetFeatureInfoResponse" );
676699
result.appendChild( getFeatureInfoElement );
677700

@@ -681,72 +704,86 @@ int QgsWMSServer::getFeatureInfo( QDomDocument& result )
681704

682705
QList<QgsMapLayer*> layerList;
683706
QgsMapLayer* currentLayer = 0;
684-
QgsPoint infoPoint; //info point in coordinates of the layer
685707
QStringList::const_iterator layerIt;
686708
for ( layerIt = queryLayerList.constBegin(); layerIt != queryLayerList.constEnd(); ++layerIt )
687709
{
688710
//create maplayers from sld parser (several layers are possible in case of feature info on a group)
689711
layerList = mConfigParser->mapLayerFromStyle( *layerIt, "" );
690712
QList<QgsMapLayer*>::iterator layerListIt = layerList.begin();
691-
for(; layerListIt != layerList.end(); ++layerListIt )
713+
for ( ; layerListIt != layerList.end(); ++layerListIt )
692714
{
693-
currentLayer = *layerListIt;
694-
if ( !currentLayer || nonIdentifiableLayers.contains( currentLayer->id() ) )
695-
{
715+
currentLayer = *layerListIt;
716+
if ( !currentLayer || nonIdentifiableLayers.contains( currentLayer->id() ) )
717+
{
696718
continue;
697-
}
698-
if ( infoPointToLayerCoordinates( i, j, infoPoint, mMapRenderer, currentLayer ) != 0 )
699-
{
719+
}
720+
721+
if ( infoPoint && infoPointToLayerCoordinates( i, j, infoPoint, mMapRenderer, currentLayer ) != 0 )
722+
{
700723
continue;
724+
}
725+
726+
QDomElement layerElement = result.createElement( "Layer" );
727+
layerElement.setAttribute( "name", currentLayer->name() );
728+
getFeatureInfoElement.appendChild( layerElement );
729+
730+
//switch depending on vector or raster
731+
QgsVectorLayer* vectorLayer = dynamic_cast<QgsVectorLayer*>( currentLayer );
732+
if ( vectorLayer )
733+
{
734+
//is there alias info for this vector layer?
735+
QMap< int, QString > layerAliasInfo;
736+
QMap< QString, QMap< int, QString > >::const_iterator aliasIt = aliasInfo.find( currentLayer->id() );
737+
if ( aliasIt != aliasInfo.constEnd() )
738+
{
739+
layerAliasInfo = aliasIt.value();
701740
}
702-
QgsDebugMsg( "Info point in layer crs: " + QString::number( infoPoint.x() ) + "//" + QString::number( infoPoint.y() ) );
703741

704-
QDomElement layerElement = result.createElement( "Layer" );
705-
layerElement.setAttribute( "name", currentLayer->name() );
706-
getFeatureInfoElement.appendChild( layerElement );
742+
//hidden attributes for this layer
743+
QSet<QString> layerHiddenAttributes;
744+
QMap< QString, QSet<QString> >::const_iterator hiddenIt = hiddenAttributes.find( currentLayer->id() );
745+
if ( hiddenIt != hiddenAttributes.constEnd() )
746+
{
747+
layerHiddenAttributes = hiddenIt.value();
748+
}
707749

708-
//switch depending on vector or raster
709-
QgsVectorLayer* vectorLayer = dynamic_cast<QgsVectorLayer*>( currentLayer );
710-
if ( vectorLayer )
750+
if ( featureInfoFromVectorLayer( vectorLayer, infoPoint, featureCount, result, layerElement, mMapRenderer, layerAliasInfo, layerHiddenAttributes, featuresRect ) != 0 )
711751
{
712-
//is there alias info for this vector layer?
713-
QMap< int, QString > layerAliasInfo;
714-
QMap< QString, QMap< int, QString > >::const_iterator aliasIt = aliasInfo.find( currentLayer->id() );
715-
if ( aliasIt != aliasInfo.constEnd() )
716-
{
717-
layerAliasInfo = aliasIt.value();
718-
}
719-
720-
//hidden attributes for this layer
721-
QSet<QString> layerHiddenAttributes;
722-
QMap< QString, QSet<QString> >::const_iterator hiddenIt = hiddenAttributes.find( currentLayer->id() );
723-
if ( hiddenIt != hiddenAttributes.constEnd() )
724-
{
725-
layerHiddenAttributes = hiddenIt.value();
726-
}
727-
728-
if ( featureInfoFromVectorLayer( vectorLayer, infoPoint, featureCount, result, layerElement, mMapRenderer, layerAliasInfo, layerHiddenAttributes ) != 0 )
729-
{
730-
continue;
731-
}
752+
continue;
732753
}
733-
else //raster layer
754+
}
755+
else //raster layer
756+
{
757+
QgsRasterLayer* rasterLayer = dynamic_cast<QgsRasterLayer*>( currentLayer );
758+
if ( rasterLayer )
734759
{
735-
QgsRasterLayer* rasterLayer = dynamic_cast<QgsRasterLayer*>( currentLayer );
736-
if ( rasterLayer )
737-
{
738-
if ( featureInfoFromRasterLayer( rasterLayer, infoPoint, result, layerElement ) != 0 )
739-
{
740-
continue;
741-
}
742-
}
743-
else
744-
{
760+
if ( featureInfoFromRasterLayer( rasterLayer, infoPoint, result, layerElement ) != 0 )
761+
{
745762
continue;
746-
}
763+
}
747764
}
765+
else
766+
{
767+
continue;
768+
}
769+
}
748770
}
749771
}
772+
773+
if ( featuresRect )
774+
{
775+
QDomElement bBoxElem = result.createElement( "BoundingBox" );
776+
bBoxElem.setAttribute( "CRS", mMapRenderer->destinationCrs().authid() );
777+
bBoxElem.setAttribute( "minx", featuresRect->xMinimum() );
778+
bBoxElem.setAttribute( "maxx", featuresRect->xMaximum() );
779+
bBoxElem.setAttribute( "miny", featuresRect->yMinimum() );
780+
bBoxElem.setAttribute( "maxy", featuresRect->yMaximum() );
781+
getFeatureInfoElement.insertBefore( bBoxElem, QDomNode() ); //insert as first child
782+
}
783+
784+
restoreLayerFilters( originalLayerFilters );
785+
delete featuresRect;
786+
delete infoPoint;
750787
return 0;
751788
}
752789

@@ -1101,29 +1138,29 @@ int QgsWMSServer::initializeSLDParser( QStringList& layersList, QStringList& sty
11011138
return 0;
11021139
}
11031140

1104-
int QgsWMSServer::infoPointToLayerCoordinates( int i, int j, QgsPoint& layerCoords, QgsMapRenderer* mapRender,
1141+
int QgsWMSServer::infoPointToLayerCoordinates( int i, int j, QgsPoint* layerCoords, QgsMapRenderer* mapRender,
11051142
QgsMapLayer* layer ) const
11061143
{
1107-
if ( !mapRender || !layer || !mapRender->coordinateTransform() )
1144+
if ( !layerCoords || !mapRender || !layer || !mapRender->coordinateTransform() )
11081145
{
11091146
return 1;
11101147
}
11111148

11121149
//first transform i,j to map output coordinates
11131150
QgsPoint mapPoint = mapRender->coordinateTransform()->toMapCoordinates( i, j );
11141151
//and then to layer coordinates
1115-
layerCoords = mapRender->mapToLayerCoordinates( layer, mapPoint );
1152+
*layerCoords = mapRender->mapToLayerCoordinates( layer, mapPoint );
11161153
return 0;
11171154
}
11181155

11191156
int QgsWMSServer::featureInfoFromVectorLayer( QgsVectorLayer* layer,
1120-
const QgsPoint& infoPoint,
1157+
const QgsPoint* infoPoint,
11211158
int nFeatures,
11221159
QDomDocument& infoDocument,
11231160
QDomElement& layerElement,
11241161
QgsMapRenderer* mapRender,
11251162
QMap<int, QString>& aliasMap,
1126-
QSet<QString>& hiddenAttributes ) const
1163+
QSet<QString>& hiddenAttributes, QgsRectangle* featureBBox ) const
11271164
{
11281165
if ( !layer || !mapRender )
11291166
{
@@ -1133,9 +1170,16 @@ int QgsWMSServer::featureInfoFromVectorLayer( QgsVectorLayer* layer,
11331170
//we need a selection rect (0.01 of map width)
11341171
QgsRectangle mapRect = mapRender->extent();
11351172
QgsRectangle layerRect = mapRender->mapToLayerCoordinates( layer, mapRect );
1136-
double searchRadius = ( layerRect.xMaximum() - layerRect.xMinimum() ) / 200;
1137-
QgsRectangle searchRect( infoPoint.x() - searchRadius, infoPoint.y() - searchRadius,
1138-
infoPoint.x() + searchRadius, infoPoint.y() + searchRadius );
1173+
1174+
QgsRectangle searchRect;
1175+
1176+
//info point could be 0 in case there is only an attribute filter
1177+
if ( infoPoint )
1178+
{
1179+
double searchRadius = ( layerRect.xMaximum() - layerRect.xMinimum() ) / 200;
1180+
searchRect.set( infoPoint->x() - searchRadius, infoPoint->y() - searchRadius,
1181+
infoPoint->x() + searchRadius, infoPoint->y() + searchRadius );
1182+
}
11391183

11401184
//do a select with searchRect and go through all the features
11411185
QgsVectorDataProvider* provider = layer->dataProvider();
@@ -1150,7 +1194,7 @@ int QgsWMSServer::featureInfoFromVectorLayer( QgsVectorLayer* layer,
11501194
const QgsFieldMap& fields = provider->fields();
11511195
bool addWktGeometry = mConfigParser && mConfigParser->featureInfoWithWktGeometry();
11521196

1153-
provider->select( provider->attributeIndexes(), searchRect, addWktGeometry, true );
1197+
provider->select( provider->attributeIndexes(), searchRect, addWktGeometry || featureBBox, true );
11541198
while ( provider->nextFeature( feature ) )
11551199
{
11561200
if ( featureCounter > nFeatures )
@@ -1188,16 +1232,25 @@ int QgsWMSServer::featureInfoFromVectorLayer( QgsVectorLayer* layer,
11881232
}
11891233

11901234
//also append the wkt geometry as an attribute
1191-
if ( addWktGeometry )
1235+
QgsGeometry* geom = feature.geometry();
1236+
if ( addWktGeometry && geom )
11921237
{
1193-
QgsGeometry* geom = feature.geometry();
1194-
if ( geom )
1238+
QDomElement geometryElement = infoDocument.createElement( "Attribute" );
1239+
geometryElement.setAttribute( "name", "geometry" );
1240+
geometryElement.setAttribute( "value", geom->exportToWkt() );
1241+
geometryElement.setAttribute( "type", "derived" );
1242+
featureElement.appendChild( geometryElement );
1243+
}
1244+
if ( featureBBox && geom && mapRender ) //extend feature info bounding box if requested
1245+
{
1246+
QgsRectangle box = mapRender->layerExtentToOutputExtent( layer, geom->boundingBox() );
1247+
if ( featureBBox->isEmpty() )
1248+
{
1249+
*featureBBox = box;
1250+
}
1251+
else
11951252
{
1196-
QDomElement geometryElement = infoDocument.createElement( "Attribute" );
1197-
geometryElement.setAttribute( "name", "geometry" );
1198-
geometryElement.setAttribute( "value", geom->exportToWkt() );
1199-
geometryElement.setAttribute( "type", "derived" );
1200-
featureElement.appendChild( geometryElement );
1253+
featureBBox->combineExtentWith( &box );
12011254
}
12021255
}
12031256
}
@@ -1207,17 +1260,17 @@ int QgsWMSServer::featureInfoFromVectorLayer( QgsVectorLayer* layer,
12071260
}
12081261

12091262
int QgsWMSServer::featureInfoFromRasterLayer( QgsRasterLayer* layer,
1210-
const QgsPoint& infoPoint,
1263+
const QgsPoint* infoPoint,
12111264
QDomDocument& infoDocument,
12121265
QDomElement& layerElement ) const
12131266
{
1214-
if ( !layer )
1267+
if ( !infoPoint || !layer )
12151268
{
12161269
return 1;
12171270
}
12181271

12191272
QMap<QString, QString> attributes;
1220-
layer->identify( infoPoint, attributes );
1273+
layer->identify( *infoPoint, attributes );
12211274

12221275
for ( QMap<QString, QString>::const_iterator it = attributes.constBegin(); it != attributes.constEnd(); ++it )
12231276
{

src/mapserver/qgswmsserver.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ class QgsCoordinateReferenceSystem;
2727
class QgsComposerLayerItem;
2828
class QgsComposerLegendItem;
2929
class QgsComposition;
30+
class QgsConfigParser;
3031
class QgsMapLayer;
3132
class QgsMapRenderer;
3233
class QgsPoint;
3334
class QgsRasterLayer;
34-
class QgsConfigParser;
35+
class QgsRectangle;
3536
class QgsVectorLayer;
3637
class QgsSymbol;
3738
class QFile;
@@ -106,14 +107,15 @@ class QgsWMSServer
106107
@param j pixel y-coordinate
107108
@param layerCoords calculated layer coordinates are assigned to this point
108109
@return 0 in case of success*/
109-
int infoPointToLayerCoordinates( int i, int j, QgsPoint& layerCoords, QgsMapRenderer* mapRender,
110+
int infoPointToLayerCoordinates( int i, int j, QgsPoint* layerCoords, QgsMapRenderer* mapRender,
110111
QgsMapLayer* layer ) const;
111112
/**Appends feature info xml for the layer to the layer element of the feature info dom document
112-
@return 0 in case of success*/
113-
int featureInfoFromVectorLayer( QgsVectorLayer* layer, const QgsPoint& infoPoint, int nFeatures, QDomDocument& infoDocument, QDomElement& layerElement, QgsMapRenderer* mapRender,
114-
QMap<int, QString>& aliasMap, QSet<QString>& hiddenAttributes ) const;
113+
@param featureBBox the bounding box of the selected features in output CRS
114+
@return 0 in case of success*/
115+
int featureInfoFromVectorLayer( QgsVectorLayer* layer, const QgsPoint* infoPoint, int nFeatures, QDomDocument& infoDocument, QDomElement& layerElement, QgsMapRenderer* mapRender,
116+
QMap<int, QString>& aliasMap, QSet<QString>& hiddenAttributes, QgsRectangle* featureBBox = 0 ) const;
115117
/**Appends feature info xml for the layer to the layer element of the dom document*/
116-
int featureInfoFromRasterLayer( QgsRasterLayer* layer, const QgsPoint& infoPoint, QDomDocument& infoDocument, QDomElement& layerElement ) const;
118+
int featureInfoFromRasterLayer( QgsRasterLayer* layer, const QgsPoint* infoPoint, QDomDocument& infoDocument, QDomElement& layerElement ) const;
117119

118120
/**Creates a layer set and returns a stringlist with layer ids that can be passed to a QgsMapRenderer. Usually used in conjunction with readLayersAndStyles*/
119121
QStringList layerSet( const QStringList& layersList, const QStringList& stylesList, const QgsCoordinateReferenceSystem& destCRS ) const;

0 commit comments

Comments
 (0)