Navigation Menu

Skip to content

Commit

Permalink
[Bugfix][Server] Use floor and ceil for round extent coordinates in s…
Browse files Browse the repository at this point in the history
…ervices capabilities
  • Loading branch information
rldhont committed Nov 21, 2019
1 parent a4a48cc commit 97e0602
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 29 deletions.
2 changes: 2 additions & 0 deletions python/server/auto_generated/qgsserverprojectutils.sip.in
Expand Up @@ -19,6 +19,8 @@
namespace QgsServerProjectUtils
{



bool owsServiceCapabilities( const QgsProject &project );
%Docstring
Returns if owsService capabilities are enabled.
Expand Down
12 changes: 12 additions & 0 deletions src/server/qgsserverprojectutils.cpp
Expand Up @@ -18,6 +18,18 @@
#include "qgsserverprojectutils.h"
#include "qgsproject.h"

double QgsServerProjectUtils::ceilWithPrecision( double number, int places )
{
double scaleFactor = std::pow( 10.0, places );
return ( std::ceil( number * scaleFactor ) / scaleFactor );
}

double QgsServerProjectUtils::floorWithPrecision( double number, int places )
{
double scaleFactor = std::pow( 10.0, places );
return ( std::floor( number * scaleFactor ) / scaleFactor );
}

bool QgsServerProjectUtils::owsServiceCapabilities( const QgsProject &project )
{
return project.readBoolEntry( QStringLiteral( "WMSServiceCapabilities" ), QStringLiteral( "/" ), false );
Expand Down
16 changes: 16 additions & 0 deletions src/server/qgsserverprojectutils.h
Expand Up @@ -20,8 +20,10 @@

#include <QString>
#include <QHash>
#include <cmath>

#include "qgis_server.h"
#include "qgis_sip.h"

class QgsProject;
class QgsRectangle;
Expand All @@ -42,6 +44,20 @@ class QgsRectangle;
namespace QgsServerProjectUtils
{

/**
* Returns a double greater than \a number to the specified number of \a places.
*
* \since QGIS 3.10.1
*/
SERVER_EXPORT double ceilWithPrecision( double number, int places ) SIP_SKIP;

/**
* Returns a double less than \a number to the specified number of \a places.
*
* \since QGIS 3.10.1
*/
SERVER_EXPORT double floorWithPrecision( double number, int places ) SIP_SKIP;

/**
* Returns if owsService capabilities are enabled.
* \param project the QGIS project
Expand Down
10 changes: 5 additions & 5 deletions src/server/services/wcs/qgswcsutils.cpp
Expand Up @@ -90,11 +90,11 @@ namespace QgsWcs
QDomElement lonLatElem = doc.createElement( QStringLiteral( "lonLatEnvelope" ) );
lonLatElem.setAttribute( QStringLiteral( "srsName" ), QStringLiteral( "urn:ogc:def:crs:OGC:1.3:CRS84" ) );
QDomElement lowerPosElem = doc.createElement( QStringLiteral( "gml:pos" ) );
QDomText lowerPosText = doc.createTextNode( qgsDoubleToString( BBox.xMinimum(), wgs84precision ) + " " + qgsDoubleToString( BBox.yMinimum(), wgs84precision ) );
QDomText lowerPosText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( BBox.xMinimum(), wgs84precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( BBox.yMinimum(), wgs84precision ), wgs84precision ) );
lowerPosElem.appendChild( lowerPosText );
lonLatElem.appendChild( lowerPosElem );
QDomElement upperPosElem = doc.createElement( QStringLiteral( "gml:pos" ) );
QDomText upperPosText = doc.createTextNode( qgsDoubleToString( BBox.xMaximum(), wgs84precision ) + " " + qgsDoubleToString( BBox.yMaximum(), wgs84precision ) );
QDomText upperPosText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( BBox.xMaximum(), wgs84precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( BBox.yMaximum(), wgs84precision ), wgs84precision ) );
upperPosElem.appendChild( upperPosText );
lonLatElem.appendChild( upperPosElem );
layerElem.appendChild( lonLatElem );
Expand Down Expand Up @@ -122,11 +122,11 @@ namespace QgsWcs
QDomElement envelopeElem = doc.createElement( QStringLiteral( "gml:Envelope" ) );
envelopeElem.setAttribute( QStringLiteral( "srsName" ), layerCrs.authid() );
QDomElement lowerCornerElem = doc.createElement( QStringLiteral( "gml:pos" ) );
QDomText lowerCornerText = doc.createTextNode( qgsDoubleToString( layerBBox.xMinimum(), precision ) + " " + qgsDoubleToString( layerBBox.yMinimum(), precision ) );
QDomText lowerCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.xMinimum(), precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.yMinimum(), wgs84precision ), precision ) );
lowerCornerElem.appendChild( lowerCornerText );
envelopeElem.appendChild( lowerCornerElem );
QDomElement upperCornerElem = doc.createElement( QStringLiteral( "gml:pos" ) );
QDomText upperCornerText = doc.createTextNode( qgsDoubleToString( layerBBox.xMaximum(), precision ) + " " + qgsDoubleToString( layerBBox.yMaximum(), precision ) );
QDomText upperCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( layerBBox.xMaximum(), precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( layerBBox.yMaximum(), wgs84precision ), precision ) );
upperCornerElem.appendChild( upperCornerText );
envelopeElem.appendChild( upperCornerElem );
spatialDomainElem.appendChild( envelopeElem );
Expand Down Expand Up @@ -159,7 +159,7 @@ namespace QgsWcs

QDomElement originElem = doc.createElement( QStringLiteral( "gml:origin" ) );
QDomElement originPosElem = doc.createElement( QStringLiteral( "gml:pos" ) );
QDomText originPosText = doc.createTextNode( qgsDoubleToString( layerBBox.xMinimum(), precision ) + " " + qgsDoubleToString( layerBBox.yMaximum(), precision ) );
QDomText originPosText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.xMinimum(), precision ), precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.yMinimum(), precision ), precision ) );
originPosElem.appendChild( originPosText );
spatialDomainElem.appendChild( originElem );

Expand Down
4 changes: 2 additions & 2 deletions src/server/services/wfs/qgswfsgetcapabilities.cpp
Expand Up @@ -613,11 +613,11 @@ namespace QgsWfs
QDomElement bBoxElement = doc.createElement( QStringLiteral( "ows:WGS84BoundingBox" ) );
bBoxElement.setAttribute( QStringLiteral( "dimensions" ), QStringLiteral( "2" ) );
QDomElement lCornerElement = doc.createElement( QStringLiteral( "ows:LowerCorner" ) );
QDomText lCornerText = doc.createTextNode( qgsDoubleToString( wgs84BoundingRect.xMinimum(), wgs84precision ) + " " + qgsDoubleToString( wgs84BoundingRect.yMinimum(), wgs84precision ) );
QDomText lCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( wgs84BoundingRect.xMinimum(), wgs84precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( wgs84BoundingRect.yMinimum(), wgs84precision ), wgs84precision ) );
lCornerElement.appendChild( lCornerText );
bBoxElement.appendChild( lCornerElement );
QDomElement uCornerElement = doc.createElement( QStringLiteral( "ows:UpperCorner" ) );
QDomText uCornerText = doc.createTextNode( qgsDoubleToString( wgs84BoundingRect.xMaximum(), wgs84precision ) + " " + qgsDoubleToString( wgs84BoundingRect.yMaximum(), wgs84precision ) );
QDomText uCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( wgs84BoundingRect.xMaximum(), wgs84precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( wgs84BoundingRect.yMaximum(), wgs84precision ), wgs84precision ) );
uCornerElement.appendChild( uCornerText );
bBoxElement.appendChild( uCornerElement );
layerElem.appendChild( bBoxElement );
Expand Down
8 changes: 4 additions & 4 deletions src/server/services/wfs/qgswfsgetcapabilities_1_0_0.cpp
Expand Up @@ -366,10 +366,10 @@ namespace QgsWfs
//create LatLongBoundingBox
QgsRectangle layerExtent = layer->extent();
QDomElement bBoxElement = doc.createElement( QStringLiteral( "LatLongBoundingBox" ) );
bBoxElement.setAttribute( QStringLiteral( "minx" ), qgsDoubleToString( layerExtent.xMinimum(), precision ) );
bBoxElement.setAttribute( QStringLiteral( "miny" ), qgsDoubleToString( layerExtent.yMinimum(), precision ) );
bBoxElement.setAttribute( QStringLiteral( "maxx" ), qgsDoubleToString( layerExtent.xMaximum(), precision ) );
bBoxElement.setAttribute( QStringLiteral( "maxy" ), qgsDoubleToString( layerExtent.yMaximum(), precision ) );
bBoxElement.setAttribute( QStringLiteral( "minx" ), qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerExtent.xMinimum(), precision ), precision ) );
bBoxElement.setAttribute( QStringLiteral( "miny" ), qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerExtent.yMinimum(), precision ), precision ) );
bBoxElement.setAttribute( QStringLiteral( "maxx" ), qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( layerExtent.xMaximum(), precision ), precision ) );
bBoxElement.setAttribute( QStringLiteral( "maxy" ), qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( layerExtent.yMaximum(), precision ), precision ) );
layerElem.appendChild( bBoxElement );

// layer metadata URL
Expand Down
24 changes: 12 additions & 12 deletions src/server/services/wms/qgswmsgetcapabilities.cpp
Expand Up @@ -1368,28 +1368,28 @@ namespace QgsWms
if ( version == QLatin1String( "1.1.1" ) ) // WMS Version 1.1.1
{
ExGeoBBoxElement = doc.createElement( QStringLiteral( "LatLonBoundingBox" ) );
ExGeoBBoxElement.setAttribute( QStringLiteral( "minx" ), qgsDoubleToString( wgs84BoundingRect.xMinimum(), wgs84precision ) );
ExGeoBBoxElement.setAttribute( QStringLiteral( "maxx" ), qgsDoubleToString( wgs84BoundingRect.xMaximum(), wgs84precision ) );
ExGeoBBoxElement.setAttribute( QStringLiteral( "miny" ), qgsDoubleToString( wgs84BoundingRect.yMinimum(), wgs84precision ) );
ExGeoBBoxElement.setAttribute( QStringLiteral( "maxy" ), qgsDoubleToString( wgs84BoundingRect.yMaximum(), wgs84precision ) );
ExGeoBBoxElement.setAttribute( QStringLiteral( "minx" ), qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( wgs84BoundingRect.xMinimum(), wgs84precision ), wgs84precision ) );
ExGeoBBoxElement.setAttribute( QStringLiteral( "miny" ), qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( wgs84BoundingRect.yMinimum(), wgs84precision ), wgs84precision ) );
ExGeoBBoxElement.setAttribute( QStringLiteral( "maxx" ), qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( wgs84BoundingRect.xMaximum(), wgs84precision ), wgs84precision ) );
ExGeoBBoxElement.setAttribute( QStringLiteral( "maxy" ), qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( wgs84BoundingRect.yMaximum(), wgs84precision ), wgs84precision ) );
}
else // WMS Version 1.3.0
{
ExGeoBBoxElement = doc.createElement( QStringLiteral( "EX_GeographicBoundingBox" ) );
QDomElement wBoundLongitudeElement = doc.createElement( QStringLiteral( "westBoundLongitude" ) );
QDomText wBoundLongitudeText = doc.createTextNode( qgsDoubleToString( wgs84BoundingRect.xMinimum(), wgs84precision ) );
QDomText wBoundLongitudeText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( wgs84BoundingRect.xMinimum(), wgs84precision ), wgs84precision ) );
wBoundLongitudeElement.appendChild( wBoundLongitudeText );
ExGeoBBoxElement.appendChild( wBoundLongitudeElement );
QDomElement eBoundLongitudeElement = doc.createElement( QStringLiteral( "eastBoundLongitude" ) );
QDomText eBoundLongitudeText = doc.createTextNode( qgsDoubleToString( wgs84BoundingRect.xMaximum(), wgs84precision ) );
QDomText eBoundLongitudeText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( wgs84BoundingRect.xMaximum(), wgs84precision ), wgs84precision ) );
eBoundLongitudeElement.appendChild( eBoundLongitudeText );
ExGeoBBoxElement.appendChild( eBoundLongitudeElement );
QDomElement sBoundLatitudeElement = doc.createElement( QStringLiteral( "southBoundLatitude" ) );
QDomText sBoundLatitudeText = doc.createTextNode( qgsDoubleToString( wgs84BoundingRect.yMinimum(), wgs84precision ) );
QDomText sBoundLatitudeText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( wgs84BoundingRect.yMinimum(), wgs84precision ), wgs84precision ) );
sBoundLatitudeElement.appendChild( sBoundLatitudeText );
ExGeoBBoxElement.appendChild( sBoundLatitudeElement );
QDomElement nBoundLatitudeElement = doc.createElement( QStringLiteral( "northBoundLatitude" ) );
QDomText nBoundLatitudeText = doc.createTextNode( qgsDoubleToString( wgs84BoundingRect.yMaximum(), wgs84precision ) );
QDomText nBoundLatitudeText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( wgs84BoundingRect.yMaximum(), wgs84precision ), wgs84precision ) );
nBoundLatitudeElement.appendChild( nBoundLatitudeText );
ExGeoBBoxElement.appendChild( nBoundLatitudeElement );
}
Expand Down Expand Up @@ -1482,10 +1482,10 @@ namespace QgsWms
crsExtent.invert();
}

bBoxElement.setAttribute( QStringLiteral( "minx" ), qgsDoubleToString( crsExtent.xMinimum(), precision ) );
bBoxElement.setAttribute( QStringLiteral( "miny" ), qgsDoubleToString( crsExtent.yMinimum(), precision ) );
bBoxElement.setAttribute( QStringLiteral( "maxx" ), qgsDoubleToString( crsExtent.xMaximum(), precision ) );
bBoxElement.setAttribute( QStringLiteral( "maxy" ), qgsDoubleToString( crsExtent.yMaximum(), precision ) );
bBoxElement.setAttribute( QStringLiteral( "minx" ), qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( crsExtent.xMinimum(), precision ), precision ) );
bBoxElement.setAttribute( QStringLiteral( "miny" ), qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( crsExtent.yMinimum(), precision ), precision ) );
bBoxElement.setAttribute( QStringLiteral( "maxx" ), qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( crsExtent.xMaximum(), precision ), precision ) );
bBoxElement.setAttribute( QStringLiteral( "maxy" ), qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( crsExtent.yMaximum(), precision ), precision ) );

QDomElement lastBBoxElem = layerElem.lastChildElement( QStringLiteral( "BoundingBox" ) );
if ( !lastBBoxElem.isNull() )
Expand Down
26 changes: 20 additions & 6 deletions src/server/services/wmts/qgswmtsgetcapabilities.cpp
Expand Up @@ -382,13 +382,14 @@ namespace QgsWmts
}

// WGS84 bounding box
int wgs84precision = 6;
QDomElement wgs84BBoxElement = doc.createElement( QStringLiteral( "ows:WGS84BoundingBox" ) );
QDomElement wgs84LowerCornerElement = doc.createElement( QStringLiteral( "LowerCorner" ) );
QDomText wgs84LowerCornerText = doc.createTextNode( qgsDoubleToString( wmtsLayer.wgs84BoundingRect.xMinimum(), 6 ) + ' ' + qgsDoubleToString( wmtsLayer.wgs84BoundingRect.yMinimum(), 6 ) );
QDomText wgs84LowerCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( wmtsLayer.wgs84BoundingRect.xMinimum(), wgs84precision ), wgs84precision ) + ' ' + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( wmtsLayer.wgs84BoundingRect.yMinimum(), wgs84precision ), wgs84precision ) );
wgs84LowerCornerElement.appendChild( wgs84LowerCornerText );
wgs84BBoxElement.appendChild( wgs84LowerCornerElement );
QDomElement wgs84UpperCornerElement = doc.createElement( QStringLiteral( "UpperCorner" ) );
QDomText wgs84UpperCornerText = doc.createTextNode( qgsDoubleToString( wmtsLayer.wgs84BoundingRect.xMaximum(), 6 ) + ' ' + qgsDoubleToString( wmtsLayer.wgs84BoundingRect.yMaximum(), 6 ) );
QDomText wgs84UpperCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( wmtsLayer.wgs84BoundingRect.xMaximum(), wgs84precision ), wgs84precision ) + ' ' + qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( wmtsLayer.wgs84BoundingRect.yMaximum(), wgs84precision ), wgs84precision ) );
wgs84UpperCornerElement.appendChild( wgs84UpperCornerText );
wgs84BBoxElement.appendChild( wgs84UpperCornerElement );
layerElem.appendChild( wgs84BBoxElement );
Expand All @@ -411,14 +412,20 @@ namespace QgsWmts
continue;
}

int precision = 3;
if ( crs.isGeographic() )
{
precision = 6;
}

QDomElement bboxElement = doc.createElement( QStringLiteral( "ows:BoundingBox" ) );
bboxElement.setAttribute( QStringLiteral( "crs" ), tms.ref );
QDomElement lowerCornerElement = doc.createElement( QStringLiteral( "LowerCorner" ) );
QDomText lowerCornerText = doc.createTextNode( qgsDoubleToString( rect.xMinimum(), 6 ) + ' ' + qgsDoubleToString( rect.yMinimum(), 6 ) );
QDomText lowerCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( rect.xMinimum(), precision ), precision ) + ' ' + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( rect.yMinimum(), precision ), precision ) );
lowerCornerElement.appendChild( lowerCornerText );
bboxElement.appendChild( lowerCornerElement );
QDomElement upperCornerElement = doc.createElement( QStringLiteral( "UpperCorner" ) );
QDomText upperCornerText = doc.createTextNode( qgsDoubleToString( rect.xMaximum(), 6 ) + ' ' + qgsDoubleToString( rect.yMaximum(), 6 ) );
QDomText upperCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( rect.xMaximum(), precision ), precision ) + ' ' + qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( rect.yMaximum(), precision ), precision ) );
upperCornerElement.appendChild( upperCornerText );
bboxElement.appendChild( upperCornerElement );
layerElem.appendChild( bboxElement );
Expand Down Expand Up @@ -532,6 +539,13 @@ namespace QgsWmts
crsElem.appendChild( crsText );
tmsElement.appendChild( crsElem );

QgsCoordinateReferenceSystem crs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( tms.ref );
int precision = 3;
if ( crs.isGeographic() )
{
precision = 6;
}

//wmts:TileMatrix
int tmIdx = 0;
for ( const tileMatrixDef &tm : tms.tileMatrixList )
Expand All @@ -551,12 +565,12 @@ namespace QgsWmts
QDomElement tmTopLeftCornerElem = doc.createElement( QStringLiteral( "TopLeftCorner" ) );
if ( tms.hasAxisInverted )
{
QDomText tmTopLeftCornerText = doc.createTextNode( qgsDoubleToString( tm.top, 6 ) + ' ' + qgsDoubleToString( tm.left, 6 ) );
QDomText tmTopLeftCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( tm.top, precision ), precision ) + ' ' + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( tm.left, precision ), precision ) );
tmTopLeftCornerElem.appendChild( tmTopLeftCornerText );
}
else
{
QDomText tmTopLeftCornerText = doc.createTextNode( qgsDoubleToString( tm.left, 6 ) + ' ' + qgsDoubleToString( tm.top, 6 ) );
QDomText tmTopLeftCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( tm.left, precision ), precision ) + ' ' + qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( tm.top, precision ), precision ) );
tmTopLeftCornerElem.appendChild( tmTopLeftCornerText );
}
tmElement.appendChild( tmTopLeftCornerElem );
Expand Down

0 comments on commit 97e0602

Please sign in to comment.