Merge branch 'master' of github.com:qgis/Quantum-GIS

This commit is contained in:
Tim Sutton 2012-09-20 17:23:16 +02:00
commit caa342b763
9 changed files with 491 additions and 147 deletions

View File

@ -4226,10 +4226,10 @@ QString QgsGeometry::exportToGeoJSON()
{
mWkt += "{ \"type\": \"Point\", \"coordinates\": [";
x = ( double * )( mGeometry + 5 );
mWkt += QString::number( *x, 'f', 6 );
mWkt += QString::number( *x, 'f' );
mWkt += ", ";
y = ( double * )( mGeometry + 5 + sizeof( double ) );
mWkt += QString::number( *y, 'f', 6 );
mWkt += QString::number( *y, 'f' );
mWkt += "] }";
return mWkt;
}
@ -4256,11 +4256,11 @@ QString QgsGeometry::exportToGeoJSON()
}
mWkt += "[";
x = ( double * ) ptr;
mWkt += QString::number( *x, 'f', 6 );
mWkt += QString::number( *x, 'f' );
mWkt += ", ";
ptr += sizeof( double );
y = ( double * ) ptr;
mWkt += QString::number( *y, 'f', 6 );
mWkt += QString::number( *y, 'f' );
ptr += sizeof( double );
if ( hasZValue )
{
@ -4313,11 +4313,11 @@ QString QgsGeometry::exportToGeoJSON()
}
mWkt += "[";
x = ( double * ) ptr;
mWkt += QString::number( *x, 'f', 6 );
mWkt += QString::number( *x, 'f' );
mWkt += ", ";
ptr += sizeof( double );
y = ( double * ) ptr;
mWkt += QString::number( *y, 'f', 6 );
mWkt += QString::number( *y, 'f' );
ptr += sizeof( double );
if ( hasZValue )
{
@ -4353,11 +4353,11 @@ QString QgsGeometry::exportToGeoJSON()
}
mWkt += "[";
x = ( double * )( ptr );
mWkt += QString::number( *x, 'f', 6 );
mWkt += QString::number( *x, 'f' );
mWkt += ", ";
ptr += sizeof( double );
y = ( double * )( ptr );
mWkt += QString::number( *y, 'f', 6 );
mWkt += QString::number( *y, 'f' );
ptr += sizeof( double );
if ( hasZValue )
{
@ -4399,11 +4399,11 @@ QString QgsGeometry::exportToGeoJSON()
}
mWkt += "[";
x = ( double * ) ptr;
mWkt += QString::number( *x, 'f', 6 );
mWkt += QString::number( *x, 'f' );
ptr += sizeof( double );
mWkt += ", ";
y = ( double * ) ptr;
mWkt += QString::number( *y, 'f', 6 );
mWkt += QString::number( *y, 'f' );
ptr += sizeof( double );
if ( hasZValue )
{
@ -4457,11 +4457,11 @@ QString QgsGeometry::exportToGeoJSON()
}
mWkt += "[";
x = ( double * ) ptr;
mWkt += QString::number( *x, 'f', 6 );
mWkt += QString::number( *x, 'f' );
ptr += sizeof( double );
mWkt += ", ";
y = ( double * ) ptr;
mWkt += QString::number( *y, 'f', 6 );
mWkt += QString::number( *y, 'f' );
ptr += sizeof( double );
if ( hasZValue )
{

View File

@ -331,7 +331,37 @@ QDomDocument QgsWFSServer::describeFeatureType()
//xsd:element
QDomElement geomElem = doc.createElement( "element"/*xsd:element*/ );
geomElem.setAttribute( "name", "geometry" );
geomElem.setAttribute( "type", "gml:GeometryPropertyType" );
QGis::WkbType wkbType = layer->wkbType();
switch ( wkbType )
{
case QGis::WKBPoint25D:
case QGis::WKBPoint:
geomElem.setAttribute( "type", "gml:PointPropertyType" );
break;
case QGis::WKBLineString25D:
case QGis::WKBLineString:
geomElem.setAttribute( "type", "gml:LineStringPropertyType" );
break;
case QGis::WKBPolygon25D:
case QGis::WKBPolygon:
geomElem.setAttribute( "type", "gml:PolygonPropertyType" );
break;
case QGis::WKBMultiPoint25D:
case QGis::WKBMultiPoint:
geomElem.setAttribute( "type", "gml:MultiPointPropertyType" );
break;
case QGis::WKBMultiLineString25D:
case QGis::WKBMultiLineString:
geomElem.setAttribute( "type", "gml:MultiLineStringPropertyType" );
break;
case QGis::WKBMultiPolygon25D:
case QGis::WKBMultiPolygon:
geomElem.setAttribute( "type", "gml:MultiPolygonPropertyType" );
break;
default:
geomElem.setAttribute( "type", "gml:GeometryPropertyType" );
break;
}
geomElem.setAttribute( "minOccurs", "0" );
geomElem.setAttribute( "maxOccurs", "1" );
sequenceElem.appendChild( geomElem );
@ -543,9 +573,11 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
}
}
if ( bboxOk )
searchRect.set( minx, miny, maxx, maxy );
QgsCoordinateReferenceSystem layerCrs = layer->crs();
startGetFeature( request, format );
startGetFeature( request, format, layerCrs, &searchRect );
if ( fidOk )
{
@ -589,8 +621,6 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
}
else
{
if ( bboxOk )
searchRect.set( minx, miny, maxx, maxy );
provider->select( attrIndexes, searchRect, mWithGeom, true );
while ( provider->nextFeature( feature ) && featureCounter < maxFeat )
{
@ -608,25 +638,102 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
return 0;
}
void QgsWFSServer::startGetFeature( QgsRequestHandler& request, const QString& format )
void QgsWFSServer::startGetFeature( QgsRequestHandler& request, const QString& format, QgsCoordinateReferenceSystem& crs, QgsRectangle* rect )
{
QByteArray result;
QString fcString;
if ( format == "GeoJSON" )
{
fcString = "{\"type\": \"FeatureCollection\",\n";
fcString += " \"bbox\": [ "+ QString::number( rect->xMinimum(), 'f' ) +", "+ QString::number( rect->yMinimum(), 'f' ) +", "+ QString::number( rect->xMaximum(), 'f' ) +", "+ QString::number( rect->yMaximum(), 'f' ) +"],\n";
fcString += " \"features\": [\n";
result = fcString.toUtf8();
request.startGetFeatureResponse( &result, format );
}
else
{
//Prepare url
//Some client requests already have http://<SERVER_NAME> in the REQUEST_URI variable
QString hrefString;
QString requestUrl = getenv( "REQUEST_URI" );
QUrl mapUrl( requestUrl );
mapUrl.setHost( QString( getenv( "SERVER_NAME" ) ) );
//Add non-default ports to url
QString portString = getenv( "SERVER_PORT" );
if ( !portString.isEmpty() )
{
bool portOk;
int portNumber = portString.toInt( &portOk );
if ( portOk )
{
if ( portNumber != 80 )
{
mapUrl.setPort( portNumber );
}
}
}
if ( QString( getenv( "HTTPS" ) ).compare( "on", Qt::CaseInsensitive ) == 0 )
{
mapUrl.setScheme( "https" );
}
else
{
mapUrl.setScheme( "http" );
}
QList<QPair<QString, QString> > queryItems = mapUrl.queryItems();
QList<QPair<QString, QString> >::const_iterator queryIt = queryItems.constBegin();
for ( ; queryIt != queryItems.constEnd(); ++queryIt )
{
if ( queryIt->first.compare( "REQUEST", Qt::CaseInsensitive ) == 0 )
{
mapUrl.removeQueryItem( queryIt->first );
mapUrl.addQueryItem( queryIt->first, "DescribeFeatureType" );
}
else if ( queryIt->first.compare( "FORMAT", Qt::CaseInsensitive ) == 0 )
{
mapUrl.removeQueryItem( queryIt->first );
}
else if ( queryIt->first.compare( "OUTPUTFORMAT", Qt::CaseInsensitive ) == 0 )
{
mapUrl.removeQueryItem( queryIt->first );
}
else if ( queryIt->first.compare( "BBOX", Qt::CaseInsensitive ) == 0 )
{
mapUrl.removeQueryItem( queryIt->first );
}
else if ( queryIt->first.compare( "FEATUREID", Qt::CaseInsensitive ) == 0 )
{
mapUrl.removeQueryItem( queryIt->first );
}
else if ( queryIt->first.compare( "FILTER", Qt::CaseInsensitive ) == 0 )
{
mapUrl.removeQueryItem( queryIt->first );
}
else if ( queryIt->first.compare( "MAXFEATURES", Qt::CaseInsensitive ) == 0 )
{
mapUrl.removeQueryItem( queryIt->first );
}
else if ( queryIt->first.compare( "PROPERTYNAME", Qt::CaseInsensitive ) == 0 )
{
mapUrl.removeQueryItem( queryIt->first );
}
else if ( queryIt->first.compare( "_DC", Qt::CaseInsensitive ) == 0 )
{
mapUrl.removeQueryItem( queryIt->first );
}
}
mapUrl.addQueryItem( "OUTPUTFORMAT", "XMLSCHEMA" );
hrefString = mapUrl.toString();
//wfs:FeatureCollection
fcString = "<wfs:FeatureCollection";
fcString += " xmlns=\"http://www.opengis.net/wfs\"";
fcString += " xmlns:wfs=\"http://www.opengis.net/wfs\"";
fcString += " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"";
fcString += " xsi:schemaLocation=\"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd\"";
fcString += " xsi:schemaLocation=\"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd http://www.opengis.net/gml "+ hrefString.replace( "&", "&amp;" ) +"\"";
fcString += " xmlns:ogc=\"http://www.opengis.net/ogc\"";
fcString += " xmlns:gml=\"http://www.opengis.net/gml\"";
fcString += " xmlns:ows=\"http://www.opengis.net/ows\"";
@ -635,6 +742,21 @@ void QgsWFSServer::startGetFeature( QgsRequestHandler& request, const QString& f
fcString += ">";
result = fcString.toUtf8();
request.startGetFeatureResponse( &result, format );
QDomDocument doc;
QDomElement bbElem = doc.createElement( "gml:boundedBy" );
QDomElement boxElem = createBoxElem( rect, doc );
if ( !boxElem.isNull() )
{
if ( crs.isValid() )
{
boxElem.setAttribute( "srsName", crs.authid() );
}
bbElem.appendChild( boxElem );
doc.appendChild( bbElem );
}
result = doc.toByteArray();
request.sendGetFeatureResponse( &result );
}
fcString = "";
}
@ -701,6 +823,10 @@ QString QgsWFSServer::createFeatureGeoJSON( QgsFeature* feat, QgsCoordinateRefer
QgsGeometry* geom = feat->geometry();
if ( geom && mWithGeom )
{
QgsRectangle box = geom->boundingBox();
fStr += " \"bbox\": [ "+ QString::number( box.xMinimum(), 'f' ) +", "+ QString::number( box.yMinimum(), 'f' ) +", "+ QString::number( box.xMaximum(), 'f' ) +", "+ QString::number( box.yMaximum(), 'f' ) +"],\n";
fStr += " \"geometry\": ";
fStr += geom->exportToGeoJSON();
fStr += ",\n";
@ -759,14 +885,25 @@ QDomElement QgsWFSServer::createFeatureElem( QgsFeature* feat, QDomDocument& doc
if ( mWithGeom )
{
//add geometry column (as gml)
QgsGeometry* geom = feat->geometry();
QDomElement geomElem = doc.createElement( "qgs:geometry" );
QDomElement gmlElem = createGeometryElem( feat->geometry(), doc );
QDomElement gmlElem = createGeometryElem( geom, doc );
if ( !gmlElem.isNull() )
{
QgsRectangle box = geom->boundingBox();
QDomElement bbElem = doc.createElement( "gml:boundedBy" );
QDomElement boxElem = createBoxElem( &box, doc );
if ( crs.isValid() )
{
boxElem.setAttribute( "srsName", crs.authid() );
gmlElem.setAttribute( "srsName", crs.authid() );
}
bbElem.appendChild( boxElem );
typeNameElement.appendChild( bbElem );
geomElem.appendChild( gmlElem );
typeNameElement.appendChild( geomElem );
}
@ -793,6 +930,27 @@ QDomElement QgsWFSServer::createFeatureElem( QgsFeature* feat, QDomDocument& doc
return featureElement;
}
QDomElement QgsWFSServer::createBoxElem( QgsRectangle* box, QDomDocument& doc ) /*const*/
{
if ( !box )
{
return QDomElement();
}
QDomElement boxElem = doc.createElement( "gml:Box" );
QVector<QgsPoint> v;
QgsPoint p1;
p1.set( box->xMinimum(), box->yMinimum() );
v.append( p1 );
QgsPoint p2;
p2.set( box->xMaximum(), box->yMaximum() );
v.append( p2 );
QDomElement coordElem = createCoordinateElem( v, doc );
boxElem.appendChild( coordElem );
return boxElem;
}
QDomElement QgsWFSServer::createGeometryElem( QgsGeometry* geom, QDomDocument& doc ) /*const*/
{
if ( !geom )
@ -931,13 +1089,13 @@ QDomElement QgsWFSServer::createPolygonElem( QgsGeometry* geom, QDomDocument& do
QString boundaryName;
if ( i == 0 )
{
boundaryName = "outerBoundaryIs";
boundaryName = "gml:outerBoundaryIs";
}
else
{
boundaryName = "innerBoundaryIs";
boundaryName = "gml:innerBoundaryIs";
}
QDomElement boundaryElem = doc.createElementNS( "http://www.opengis.net/gml", boundaryName );
QDomElement boundaryElem = doc.createElement( boundaryName );
QDomElement ringElem = doc.createElement( "gml:LinearRing" );
QDomElement coordElem = createCoordinateElem( poly.at( i ), doc );
ringElem.appendChild( coordElem );
@ -979,7 +1137,7 @@ QDomElement QgsWFSServer::createCoordinateElem( const QVector<QgsPoint> points,
coordElem.setAttribute( "ts", " " );
//precision 4 for meters / feet, precision 8 for degrees
int precision = 8;
int precision = 6;
/*
if ( mSourceCRS.mapUnits() == QGis::Meters
|| mSourceCRS.mapUnits() == QGis::Feet )
@ -996,9 +1154,9 @@ QDomElement QgsWFSServer::createCoordinateElem( const QVector<QgsPoint> points,
{
coordString += " ";
}
coordString += QString::number( pointIt->x(), 'f', precision );
coordString += QString::number( pointIt->x(), 'f');
coordString += ",";
coordString += QString::number( pointIt->y(), 'f', precision );
coordString += QString::number( pointIt->y(), 'f' );
}
QDomText coordText = doc.createTextNode( coordString );

View File

@ -36,6 +36,7 @@ class QgsVectorLayer;
class QgsCoordinateReferenceSystem;
class QgsField;
class QgsFeature;
class QgsRectangle;
class QgsGeometry;
class QgsSymbol;
class QgsRequestHandler;
@ -80,7 +81,7 @@ class QgsWFSServer
protected:
void startGetFeature( QgsRequestHandler& request, const QString& format );
void startGetFeature( QgsRequestHandler& request, const QString& format, QgsCoordinateReferenceSystem& crs, QgsRectangle* rect );
void sendGetFeature( QgsRequestHandler& request, const QString& format, QgsFeature* feat, int featIdx, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet<QString> hiddenAttributes );
void endGetFeature( QgsRequestHandler& request, const QString& format );
@ -90,6 +91,7 @@ class QgsWFSServer
//methods to write GML2
QDomElement createFeatureElem( QgsFeature* feat, QDomDocument& doc, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet<QString> hiddenAttributes ) /*const*/;
QDomElement createBoxElem( QgsRectangle* box, QDomDocument& doc ) /* const */;
QDomElement createGeometryElem( QgsGeometry* g, QDomDocument& doc ) /*const*/;
QDomElement createLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const;
QDomElement createMultiLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const;

View File

@ -754,7 +754,7 @@ bool QgsWcsCapabilities::parseDescribeCoverageDom10( QByteArray const &xml, QgsW
// may be GTiff, GeoTIFF, TIFF, GIF, ....
coverage->supportedFormat = domElementsTexts( coverageOfferingElement, "supportedFormats.formats" );
//QgsDebugMsg( "supportedFormat = " + coverage->supportedFormat.join( "," ) );
QgsDebugMsg( "supportedFormat = " + coverage->supportedFormat.join( "," ) );
// spatialDomain and Grid/RectifiedGrid are optional according to specificationi.
// If missing, we cannot get native resolution and size.

View File

@ -804,11 +804,17 @@ void QgsWcsProvider::cacheReplyFinished()
QgsDebugMsg( "contentType: " + contentType );
// Exception
// Content type examples: text/xml
// application/vnd.ogc.se_xml;charset=UTF-8
// application/xml
if ( contentType.startsWith( "text/", Qt::CaseInsensitive ) ||
contentType.toLower() == "application/vnd.ogc.se_xml" )
contentType.toLower() == "application/xml" ||
contentType.startsWith( "application/vnd.ogc.se_xml", Qt::CaseInsensitive ) )
{
QByteArray text = mCacheReply->readAll();
if (( contentType.toLower() == "text/xml" || contentType.toLower() == "application/vnd.ogc.se_xml" )
if (( contentType.toLower() == "text/xml" ||
contentType.toLower() == "application/xml" ||
contentType.startsWith( "application/vnd.ogc.se_xml", Qt::CaseInsensitive ) )
&& parseServiceExceptionReportDom( text ) )
{
QgsMessageLog::logMessage( tr( "Map request error (Title:%1; Error:%2; URL: %3)" )

View File

@ -54,7 +54,7 @@ class QgsExpressionOGCVisitor : public QgsExpression::Visitor
case QgsExpression::boEQ: opName = "PropertyIsEqualTo"; break;
case QgsExpression::boNE: opName = "PropertyIsNotEqualTo"; break;
case QgsExpression::boLE: opName = "PropertyIsLessThanOrEqualTo"; break;
case QgsExpression::boGE: opName = "PropertyIsLessThanOrEqualTo"; break;
case QgsExpression::boGE: opName = "PropertyIsGreaterThanOrEqualTo"; break;
case QgsExpression::boLT: opName = "PropertyIsLessThan"; break;
case QgsExpression::boGT: opName = "PropertyIsGreaterThan"; break;
case QgsExpression::boOr: opName = "Or"; break;

View File

@ -77,17 +77,25 @@ void TestQgsWcsPublicServers::init()
QCoreApplication::exit( 1 );
}
}
mHead << "Coverage";
mHead << "Version";
mHead << "Snap";
mHead << "Bands";
mHead << "Type";
mHead << "Min";
mHead << "Max";
mHead << "Values";
mHead << "Colors";
mHead << "Has size";
QStringList providers;
providers << "wcs" << "gdal";
foreach ( QString provider, providers )
{
QString prefix = provider == "gdal" ? "GDAL " : "";
mHead << prefix + "CRS";
mHead << prefix + "Snap";
mHead << prefix + "Bands";
mHead << prefix + "Type";
mHead << prefix + "Min";
mHead << prefix + "Max";
mHead << prefix + "Values";
mHead << prefix + "Colors";
}
// read servers + issues list
QString path = QgsApplication::pkgDataPath() + "/resources/wcs-servers.json";
QFile file( path );
@ -109,6 +117,7 @@ void TestQgsWcsPublicServers::init()
QgsDebugMsg( "serverUrl: " + serverUrl );
Server server( serverUrl );
server.description = serverValue.property( "description" ).toString();
QScriptValue issuesValue = serverValue.property( "issues" );
@ -122,6 +131,8 @@ void TestQgsWcsPublicServers::init()
QgsDebugMsg( "description: " + description );
Issue issue( description );
issue.offender = issueValue.property( "offender" ).toString();
QScriptValue coveragesValue = issueValue.property( "coverages" );
QScriptValueIterator coveragesIt( coveragesValue );
while ( coveragesIt.hasNext() )
@ -150,9 +161,18 @@ void TestQgsWcsPublicServers::init()
}
}
QStringList TestQgsWcsPublicServers::issueDescriptions( const QString & url, const QString & coverage, const QString &version )
TestQgsWcsPublicServers::Server TestQgsWcsPublicServers::getServer( const QString & url )
{
QStringList descriptions;
foreach ( Server server, mServers )
{
if ( server.url == url ) return server;
}
return Server();
}
QList<TestQgsWcsPublicServers::Issue> TestQgsWcsPublicServers::issues( const QString & url, const QString & coverage, const QString &version )
{
QList<Issue> issues;
foreach ( Server server, mServers )
{
if ( server.url == url )
@ -162,14 +182,41 @@ QStringList TestQgsWcsPublicServers::issueDescriptions( const QString & url, con
if (( issue.coverages.size() == 0 || issue.coverages.contains( coverage ) ) &&
( issue.versions.size() == 0 || issue.versions.contains( version ) ) )
{
descriptions << issue.description;
issues << issue;
}
}
}
}
return issues;
}
QStringList TestQgsWcsPublicServers::issueDescriptions( const QString & url, const QString & coverage, const QString &version )
{
QStringList descriptions;
foreach ( Issue myIssue, issues( url, coverage, version ) )
{
descriptions << myIssue.description;
}
return descriptions;
}
int TestQgsWcsPublicServers::issueOffender( const QString & url, const QString & coverage, const QString &version )
{
int offender = NoOffender;
foreach ( Issue myIssue, issues( url, coverage, version ) )
{
if ( myIssue.offender == "server" )
{
offender |= ServerOffender;
}
else
{
offender |= QGisOffender;
}
}
return offender;
}
void TestQgsWcsPublicServers::test( )
{
QStringList versions;
@ -183,7 +230,9 @@ void TestQgsWcsPublicServers::test( )
}
else
{
versions << "" << "1.0.0" << "1.1.0"; // empty for default
//versions << "" << "1.0.0" << "1.1.0"; // empty for default
// Empty is version is the same like "1.0.0" because QGIS will try "1.0.0" first
versions << "1.0.0" << "1.1.0";
}
@ -263,6 +312,7 @@ void TestQgsWcsPublicServers::test( )
continue;
}
myVersionLog << QString( "totalCoverages:%1" ).arg( myCoverages.size() );
int myCoverageCount = 0;
int myStep = myCoverages.size() / qMin( mMaxCoverages, myCoverages.size() );
@ -291,8 +341,6 @@ void TestQgsWcsPublicServers::test( )
QString myPath = myVersionDirPath + QDir::separator() + myCoverage.identifier;
QString myLogPath = myPath + ".log";
QString myPngPath = myPath + ".png";
QgsDebugMsg( "myPngPath = " + myPngPath );
if ( QFileInfo( myLogPath ).exists() && !mForce )
{
@ -325,80 +373,111 @@ void TestQgsWcsPublicServers::test( )
}
myLog << QString( "hasSize:%1" ).arg( myCoverage.hasSize );
QgsRasterLayer * myLayer = new QgsRasterLayer( myUri.encodedUri(), myCoverage.identifier, "wcs", true );
if ( myLayer->isValid() )
{
int myBandCount = myLayer->dataProvider()->bandCount();
myLog << "bandCount:" + QString::number( myBandCount );
if ( myBandCount > 0 )
{
myLog << "srcType:" + QString::number( myLayer->dataProvider()->srcDataType( 1 ) );
// Test QGIS provider and via GDAL
QStringList providers;
providers << "wcs" << "gdal";
QgsRasterBandStats myStats = myLayer->dataProvider()->bandStatistics( 1, QgsRasterBandStats::All, QgsRectangle(), myWidth * myHeight );
myLog << "min:" + QString::number( myStats.minimumValue );
myLog << "max:" + QString::number( myStats.maximumValue );
foreach ( QString provider, providers )
{
QString uri;
if ( provider == "wcs" )
{
uri = myUri.encodedUri();
}
else // gdal
{
uri = myPath + "-gdal.xml";
QFile myGdalXmlFile( uri );
myGdalXmlFile.open( QIODevice::WriteOnly | QIODevice::Text );
QTextStream myStream( &myGdalXmlFile );
myStream << "<WCS_GDAL>\n";
myStream << " <ServiceURL>" + serverUrl + "?" + "</ServiceURL>\n";
myStream << " <CoverageName>" + myCoverage.identifier + "</CoverageName>\n";
myStream << " <Version>" + version + "</Version>\n";
myStream << " <Timeout>60</Version>\n";
myStream << "</WCS_GDAL>\n";
myGdalXmlFile.close();
}
QgsMapRenderer myMapRenderer;
QList<QgsMapLayer *> myLayersList;
myLayersList.append( myLayer );
QgsMapLayerRegistry::instance()->addMapLayers( myLayersList, false );
QMap<QString, QgsMapLayer*> myLayersMap = QgsMapLayerRegistry::instance()->mapLayers();
myMapRenderer.setLayerSet( myLayersMap.keys() );
myMapRenderer.setExtent( myLayer->extent() );
QImage myImage( myWidth, myHeight, QImage::Format_ARGB32_Premultiplied );
myImage.fill( 0 );
myMapRenderer.setOutputSize( QSize( myWidth, myHeight ), myImage.logicalDpiX() );
QPainter myPainter( &myImage );
myMapRenderer.render( &myPainter );
// Save rendered image
myImage.save( myPngPath );
// Verify data
QSet<QString> myValues; // cannot be QSet<double>
void *myData = myLayer->dataProvider()->readBlock( 1, myLayer->extent(), myWidth, myHeight );
if ( myData )
QgsRasterLayer * myLayer = new QgsRasterLayer( uri, myCoverage.identifier, provider, true );
if ( myLayer->isValid() )
{
int myType = myLayer->dataProvider()->dataType( 1 );
myLog << provider + "_crs:" + myLayer->dataProvider()->crs().authid();
int myBandCount = myLayer->dataProvider()->bandCount();
myLog << provider + "_bandCount:" + QString::number( myBandCount );
if ( myBandCount > 0 )
{
myLog << provider + "_srcType:" + QString::number( myLayer->dataProvider()->srcDataType( 1 ) );
QgsRasterBandStats myStats = myLayer->dataProvider()->bandStatistics( 1, QgsRasterBandStats::All, QgsRectangle(), myWidth * myHeight );
myLog << provider + "_min:" + QString::number( myStats.minimumValue );
myLog << provider + "_max:" + QString::number( myStats.maximumValue );
}
QgsMapRenderer myMapRenderer;
QList<QgsMapLayer *> myLayersList;
myLayersList.append( myLayer );
QgsMapLayerRegistry::instance()->addMapLayers( myLayersList, false );
QMap<QString, QgsMapLayer*> myLayersMap = QgsMapLayerRegistry::instance()->mapLayers();
myMapRenderer.setLayerSet( myLayersMap.keys() );
myMapRenderer.setExtent( myLayer->extent() );
QImage myImage( myWidth, myHeight, QImage::Format_ARGB32_Premultiplied );
myImage.fill( 0 );
myMapRenderer.setOutputSize( QSize( myWidth, myHeight ), myImage.logicalDpiX() );
QPainter myPainter( &myImage );
myMapRenderer.render( &myPainter );
// Save rendered image
QString myPngPath = myPath + "-" + provider + ".png";
QgsDebugMsg( "myPngPath = " + myPngPath );
myImage.save( myPngPath );
// Verify data
QSet<QString> myValues; // cannot be QSet<double>
void *myData = myLayer->dataProvider()->readBlock( 1, myLayer->extent(), myWidth, myHeight );
if ( myData )
{
int myType = myLayer->dataProvider()->dataType( 1 );
for ( int row = 0; row < myHeight; row++ )
{
for ( int col = 0; col < myWidth; col++ )
{
double value = myLayer->dataProvider()->readValue( myData, myType, row * myWidth + col );
QString valueStr = QString::number( value );
if ( !myValues.contains( valueStr ) ) myValues.insert( valueStr );
}
}
free( myData );
}
QgsDebugMsg( QString( "%1 values" ).arg( myValues.size() ) );
myLog << provider + QString( "_valuesCount:%1" ).arg( myValues.size() );
// Verify image colors
QSet<QRgb> myColors;
for ( int row = 0; row < myHeight; row++ )
{
for ( int col = 0; col < myWidth; col++ )
{
double value = myLayer->dataProvider()->readValue( myData, myType, row * myWidth + col );
QString valueStr = QString::number( value );
if ( !myValues.contains( valueStr ) ) myValues.insert( valueStr );
QRgb color = myImage.pixel( col, row );
if ( !myColors.contains( color ) ) myColors.insert( color );
}
}
free( myData );
QgsDebugMsg( QString( "%1 colors" ).arg( myColors.size() ) );
myLog << provider + QString( "_colorsCount:%1" ).arg( myColors.size() );
}
QgsDebugMsg( QString( "%1 values" ).arg( myValues.size() ) );
myLog << QString( "valuesCount:%1" ).arg( myValues.size() );
// Verify image colors
QSet<QRgb> myColors;
for ( int row = 0; row < myHeight; row++ )
else
{
for ( int col = 0; col < myWidth; col++ )
{
QRgb color = myImage.pixel( col, row );
if ( !myColors.contains( color ) ) myColors.insert( color );
}
QgsDebugMsg( "Layer is not valid" );
myLog << provider + "_error:Layer is not valid";
}
QgsDebugMsg( QString( "%1 colors" ).arg( myColors.size() ) );
myLog << QString( "colorsCount:%1" ).arg( myColors.size() );
}
else
{
QgsDebugMsg( "Layer is not valid" );
myLog << "error:Layer is not valid";
}
QFile myLogFile( myLogPath );
@ -461,6 +540,11 @@ void TestQgsWcsPublicServers::report()
QMap<QString, QString> myServerLog = readLog( myServerLogPath );
myReport += QString( "<h2>Server: %1</h2>" ).arg( myServerLog.value( "server" ) );
Server myServer = getServer( myServerLog.value( "server" ) );
if ( !myServer.description.isEmpty() )
{
myReport += myServer.description + "<br>";
}
QString myServerReport;
@ -506,52 +590,92 @@ void TestQgsWcsPublicServers::report()
QString myLogPath = myVersionDir.absolutePath() + QDir::separator() + myLogFileName;
QMap<QString, QString>myLog = readLog( myLogPath );
myVersionReport += "<tr>";
QStringList myValues;
myValues << QString( "<a href='%1'>%2</a>" ).arg( myLog.value( "describeCoverageUrl" ) ).arg( myLog.value( "identifier" ) );
myValues << myLog.value( "version" );
QString imgPath = myVersionDir.absolutePath() + QDir::separator() + QFileInfo( myLogPath ).completeBaseName() + ".png";
myValues << myLog.value( "hasSize" );
myVersionReport += cells( myValues );
myValues.clear();
if ( !myLog.value( "error" ).isEmpty() )
QStringList providers;
providers << "wcs" << "gdal";
foreach ( QString provider, providers )
{
myValues << myLog.value( "error" );
QStringList issues = issueDescriptions( myServerLog.value( "server" ), myLog.value( "identifier" ), myLog.value( "version" ) );
myValues << issues.join( "<br>" );
myVersionReport += row( myValues, "cellerr" );
myVersionErrCount++;
}
else
{
myValues << "<img src='" + imgPath + "'>";
myValues << myLog.value( "bandCount" );
myValues << myLog.value( "srcType" );
myValues << myLog.value( "min" );
myValues << myLog.value( "max" );
myValues << myLog.value( "valuesCount" );
myValues << myLog.value( "colorsCount" );
myValues << myLog.value( "hasSize" );
QString cls;
int myValuesCount = myLog.value( "valuesCount" ).toInt();
int myColorsCount = myLog.value( "colorsCount" ).toInt();
if ( myValuesCount < 4 )
{
cls = "cellerr";
myVersionErrCount++;
myCoverageErrCount++;
}
else if ( myColorsCount < 4 )
{
cls = "cellwarn";
myVersionWarnCount++;
myCoverageWarnCount++;
}
QString imgPath = myVersionDir.absolutePath() + QDir::separator() + QFileInfo( myLogPath ).completeBaseName() + "-" + provider + ".png";
myVersionReport += row( myValues, cls );
if ( !myLog.value( provider + "_error" ).isEmpty() )
{
myValues << myLog.value( provider + "_error" );
int offender = NoOffender;
if ( provider == "wcs" )
{
QStringList issues = issueDescriptions( myServerLog.value( "server" ), myLog.value( "identifier" ), myLog.value( "version" ) );
myValues << issues.join( "<br>" );
offender = issueOffender( myServerLog.value( "server" ), myLog.value( "identifier" ), myLog.value( "version" ) );
myVersionErrCount++;
}
QString cls;
if ( offender == ServerOffender )
{
cls = "cell-err-server";
}
else if ( offender == QGisOffender )
{
cls = "cell-err-qgis";
}
else
{
cls = "cell-err";
}
myVersionReport += cells( myValues, cls, 8 );
myValues.clear();
}
else
{
myValues << myLog.value( provider + "_crs" );
myValues << "<img src='" + imgPath + "'>";
myValues << myLog.value( provider + "_bandCount" );
myValues << myLog.value( provider + "_srcType" );
myValues << myLog.value( provider + "_min" );
myValues << myLog.value( provider + "_max" );
myValues << myLog.value( provider + "_valuesCount" );
myValues << myLog.value( provider + "_colorsCount" );
QString cls;
int myValuesCount = myLog.value( provider + "_valuesCount" ).toInt();
int myColorsCount = myLog.value( provider + "_colorsCount" ).toInt();
if ( myValuesCount < 4 )
{
cls = "cell-err";
if ( provider == "wcs" )
{
myVersionErrCount++;
myCoverageErrCount++;
}
}
else if ( myColorsCount < 4 )
{
cls = "cell-warn";
if ( provider == "wcs" )
{
myVersionWarnCount++;
myCoverageWarnCount++;
}
}
myVersionReport += cells( myValues, cls );
myValues.clear();
}
}
myVersionReport += "<tr>\n";
} // coverages
myVersionReport += "</table>\n";
// prepend counts
myVersionReport.prepend( QString( "<b>Coverages: %1</b><br>\n" ).arg( myVersionCoverageCount ) +
myVersionReport.prepend( QString( "<b>Total coverages: %1</b><br>\n" ).arg( myVersionLog.value( "totalCoverages" ) ) +
QString( "<b>Tested coverages: %1</b><br>\n" ).arg( myVersionCoverageCount ) +
QString( "<b>Errors: %1</b><br>\n" ).arg( myVersionErrCount ) +
QString( "<b>Warnings: %1</b><br><br>" ).arg( myVersionWarnCount ) );
myServerReport += myVersionReport;
@ -572,10 +696,12 @@ void TestQgsWcsPublicServers::report()
myRep += "<style>";
myRep += ".tab { border-spacing: 0px; border-width: 1px 1px 0 0; border-style: solid; }";
myRep += ".cell { border-width: 0 0 1px 1px; border-style: solid; font-size: smaller; text-align: center}";
//myReport += ".cellok { background: #00ff00; }";
myRep += ".cellok { background: #ffffff; }";
myRep += ".cellwarn { background: #ffcc00; }";
myRep += ".cellerr { background: #ff0000; }";
//myReport += ".cell-ok { background: #00ff00; }";
myRep += ".cell-ok { background: #ffffff; }";
myRep += ".cell-warn { background: #ffcc00; }";
myRep += ".cell-err { background: #ff0000; }";
myRep += ".cell-err-server { background: #ffff00; }";
myRep += ".cell-err-qgis { background: #ff0000; }";
myRep += ".errmsg { color: #ff0000; }";
myRep += "</style>";
@ -618,6 +744,22 @@ QString TestQgsWcsPublicServers::error( QString theMessage )
return myRow;
}
QString TestQgsWcsPublicServers::cells( QStringList theValues, QString theClass, int colspan )
{
QString myRow;
for ( int i = 0; i < theValues.size(); i++ )
{
QString val = theValues.value( i );
QString colspanStr;
if ( colspan > 1 && i == theValues.size() - 1 )
{
colspanStr = QString( "colspan=%1" ).arg( colspan - theValues.size() + 1 ) ;
}
myRow += QString( "<td class='cell %1' %2>%3</td>" ).arg( theClass ).arg( colspanStr ).arg( val );
}
return myRow;
}
QString TestQgsWcsPublicServers::row( QStringList theValues, QString theClass )
{
QString myRow = "<tr>";

View File

@ -35,6 +35,7 @@ class TestQgsWcsPublicServers: public QObject
// Known problem
struct Issue
{
QString offender; // server or empty == qgis
QStringList versions; // version regex
QStringList coverages; // coverage regex
QString description; // problem description
@ -45,9 +46,16 @@ class TestQgsWcsPublicServers: public QObject
Server( ) {}
Server( const QString & u ) : url( u ) {}
QString url; // URL
QString description; // notes
QList<TestQgsWcsPublicServers::Issue> issues;
};
enum OffenderType
{
NoOffender = 0,
ServerOffender = 1,
QGisOffender = 1 << 1
};
TestQgsWcsPublicServers( const QString & cacheDirPath, int maxCoverages, const QString & server = QString(), const QString & coverage = QString(), const QString &version = QString(), bool force = false );
@ -55,14 +63,20 @@ class TestQgsWcsPublicServers: public QObject
void test();
void report();
private:
QString cells( QStringList theValues, QString theClass = QString(), int colspan = 1 );
QString row( QStringList theValues, QString theClass = QString() );
QString error( QString theMessage );
void writeReport( QString theReport );
QMap<QString, QString> readLog( QString theFileName );
Server getServer( const QString & url );
QList<Issue> issues( const QString & url, const QString & coverage, const QString &version );
QStringList issueDescriptions( const QString & url, const QString & coverage, const QString &version );
int issueOffender( const QString & url, const QString & coverage, const QString &version );
QString mCacheDirPath;
QDir mCacheDir;

View File

@ -1,11 +1,33 @@
[
{
url: 'http://demo.opengeo.org/geoserver/wcs',
description: 'Does not work at all with gvSIG-1_11-1305-final.',
issues: [
{
offender: 'server',
coverages: [ 'og:0' ],
versions: [ ],
description: 'Server fails on DescribeCoverage with: java.io.IOException null Translator error Unexpected error occurred during describe coverage xml encoding ...'
versions: [ '1.0.0' ],
description: 'The server fails in DescribeCoverage with: java.io.IOException null Translator error Unexpected error occurred during describe coverage xml encoding ...'
},{
offender: 'server',
coverages: [ 'bm' ],
versions: [ '1.1.0' ],
description: 'The server fails in DescribeCoverage with: java.io.IOException null Translator error Unexpected error occurred during describe coverage xml encoding ...'
},{
offender: 'server',
coverages: [ 'usgs:nlcd', 'nlcd' ],
versions: [ '1.0.0', '1.1.0' ],
description: 'The server does no offer any CRS in DescribeCoverage supportedCRSs / supportedCRS. QGIS tries to get coverage using EPSG:5070, in which the coverage spatialDomain.Envelope is defined, but server fails reporting error: Could not recognize crs ...'
},{
offender: 'server',
coverages: [ '0', 'naturalearth' ],
versions: [ '1.1.0' ],
description: "The server fails in GetCoverage with 'java.lang.IllegalArgumentException: xScale:the parameter value is not valid. xScale:the parameter value is not valid.' It fails with BOUNDINGBOX=-2,-6,2,6&GRIDORIGIN=2,-6&GRIDOFFSETS=-2,3 but works with BOUNDINGBOX=-2,-6,2,6&GRIDORIGIN=2,-6&GRIDOFFSETS=2,-3 (GRIDOFFSETS signs switched) other coverages (Arc_Sample e.g.) work OK with the first"
},{
offender: 'server',
coverages: [ 'Img_Sample' ],
versions: [ '1.1.0' ],
description: "The server fails in GetCoverage with 'java.lang.IllegalArgumentException: The specified dimensional parameter is non-positive. The specified dimensional parameter is non-positive'."
}
]
}, {