[FEATURE:] Redlining in QGIS server (GetMap and GetPrint). Funded by canton of Solothurn

This commit is contained in:
Marco Hugentobler 2016-03-29 11:25:12 +02:00
parent befa962b30
commit afa20ec28d
6 changed files with 326 additions and 30 deletions

View File

@ -25,6 +25,8 @@
#include <QHash>
class QgsMapLayer;
class QgsOWSServer
{
public:

View File

@ -717,11 +717,11 @@ bool QgsSLDConfigParser::WMSInspireActivated() const
return false;
}
QgsComposition* QgsSLDConfigParser::createPrintComposition( const QString& composerTemplate, QgsMapRenderer* mapRenderer, const QMap< QString, QString >& parameterMap ) const
QgsComposition* QgsSLDConfigParser::createPrintComposition( const QString& composerTemplate, QgsMapRenderer* mapRenderer, const QMap< QString, QString >& parameterMap, QStringList& highlightLayers ) const
{
if ( mFallbackParser )
{
return mFallbackParser->createPrintComposition( composerTemplate, mapRenderer, parameterMap );
return mFallbackParser->createPrintComposition( composerTemplate, mapRenderer, parameterMap, highlightLayers );
}
return nullptr;
}

View File

@ -112,7 +112,7 @@ class QgsSLDConfigParser : public QgsWMSConfigParser
//printing
/** Creates a print composition, usually for a GetPrint request. Replaces map and label parameters*/
QgsComposition* createPrintComposition( const QString& composerTemplate, QgsMapRenderer* mapRenderer, const QMap< QString, QString >& parameterMap ) const;
QgsComposition* createPrintComposition( const QString& composerTemplate, QgsMapRenderer* mapRenderer, const QMap< QString, QString >& parameterMap, QStringList& highlightLayers ) const;
/** Creates a composition from the project file (probably delegated to the fallback parser)*/
QgsComposition* initComposition( const QString& composerTemplate, QgsMapRenderer* mapRenderer, QList< QgsComposerMap*>& mapList, QList< QgsComposerLegend* >& legendList, QList< QgsComposerLabel* >& labelList, QList<const QgsComposerHtml *>& htmlFrameList ) const override;

View File

@ -17,6 +17,7 @@
#include "qgswmsconfigparser.h"
#include "qgsmaplayer.h"
#include "qgsmaplayerregistry.h"
#include "qgsmapserviceexception.h"
#include "qgscomposerlabel.h"
@ -30,6 +31,10 @@
#include "qgslayertreegroup.h"
#include "qgslayertreelayer.h"
#include "qgsrendererv2.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
QgsWMSConfigParser::QgsWMSConfigParser()
{
@ -40,7 +45,7 @@ QgsWMSConfigParser::~QgsWMSConfigParser()
}
QgsComposition* QgsWMSConfigParser::createPrintComposition( const QString& composerTemplate, QgsMapRenderer* mapRenderer, const QMap< QString, QString >& parameterMap ) const
QgsComposition* QgsWMSConfigParser::createPrintComposition( const QString& composerTemplate, QgsMapRenderer* mapRenderer, const QMap< QString, QString >& parameterMap, QStringList& highlightLayers ) const
{
QList<QgsComposerMap*> composerMaps;
QList<QgsComposerLegend*> composerLegends;
@ -133,56 +138,74 @@ QgsComposition* QgsWMSConfigParser::createPrintComposition( const QString& compo
}
//layers / styles
QString layers = parameterMap.value( mapId + ":LAYERS" );
QString styles = parameterMap.value( mapId + ":STYLES" );
if ( !layers.isEmpty() )
QStringList layerSet;
if ( currentMap->keepLayerSet() )
{
QStringList layerSet;
QStringList wmsLayerList = layers.split( ",", QString::SkipEmptyParts );
layerSet = currentMap->layerSet();
}
else
{
QString layers = parameterMap.value( mapId + ":LAYERS" );
QString styles = parameterMap.value( mapId + ":STYLES" );
if ( layers.isEmpty() )
{
layers = parameterMap.value( "LAYERS" );
styles = parameterMap.value( "STYLES" );
}
QStringList wmsLayerList = layers.split( "," );
QStringList wmsStyleList;
if ( !styles.isEmpty() )
{
wmsStyleList = styles.split( ",", QString::SkipEmptyParts );
wmsStyleList = styles.split( "," );
}
for ( int i = 0; i < wmsLayerList.size(); ++i )
{
QString wmsLayer = wmsLayerList.at( i );
QString styleName;
if ( wmsStyleList.size() > i )
{
styleName = wmsStyleList.at( i );
}
bool allowCaching = true;
if ( wmsLayerList.count( wmsLayer ) > 1 )
foreach ( QgsMapLayer *layer, mapLayerFromStyle( wmsLayerList.at( i ), styleName ) )
{
allowCaching = false;
}
QList<QgsMapLayer*> layerList = mapLayerFromStyle( wmsLayer, styleName, allowCaching );
int listIndex;
for ( listIndex = 0; listIndex < layerList.size(); listIndex++ )
{
QgsMapLayer* layer = layerList.at( listIndex );
if ( layer )
{
layerSet.push_back( layer->id() );
}
}
}
}
currentMap->setLayerSet( layerSet );
currentMap->setKeepLayerSet( true );
//save layer list prior to adding highlight layers
QStringList bkLayerSet = layerSet;
//add highlight layers
highlightLayers.append( addHighlightLayers( parameterMap, layerSet, mapId + ":" ) );
currentMap->setLayerSet( layerSet );
currentMap->setKeepLayerSet( true );
//remove highlight layers from the composer legends
QList< QgsComposerLegend* >::iterator legendIt = composerLegends.begin();
for ( ; legendIt != composerLegends.end(); ++legendIt )
{
if (( *legendIt )->model()->autoUpdate() )
{
( *legendIt )->model()->setLayerSet( bkLayerSet );
}
}
//grid space x / y
currentMap->grid()->setIntervalX( parameterMap.value( mapId + ":GRID_INTERVAL_X" ).toDouble() );
currentMap->grid()->setIntervalY( parameterMap.value( mapId + ":GRID_INTERVAL_Y" ).toDouble() );
}
//update legend
// if it has an auto-update model
//update legend
// if it has an auto-update model
Q_FOREACH ( QgsComposerLegend* currentLegend, composerLegends )
{
if ( !currentLegend )
@ -243,7 +266,7 @@ QgsComposition* QgsWMSConfigParser::createPrintComposition( const QString& compo
}
}
//replace label text
//replace label text
Q_FOREACH ( QgsComposerLabel *currentLabel, composerLabels )
{
QString title = parameterMap.value( currentLabel->id().toUpper() );
@ -263,7 +286,7 @@ QgsComposition* QgsWMSConfigParser::createPrintComposition( const QString& compo
currentLabel->setText( title );
}
//replace html url
//replace html url
Q_FOREACH ( const QgsComposerHtml *currentHtml, composerHtmls )
{
QgsComposerHtml * html = const_cast<QgsComposerHtml *>( currentHtml );
@ -294,3 +317,252 @@ QgsComposition* QgsWMSConfigParser::createPrintComposition( const QString& compo
return c;
}
QStringList QgsWMSConfigParser::addHighlightLayers( const QMap<QString, QString>& parameterMap, QStringList& layerSet, const QString& parameterPrefix )
{
QStringList highlightLayers, geomSplit, symbolSplit, labelSplit, labelFontSplit, labelSizeSplit,
labelWeightSplit, labelColorSplit, labelBufferColorSplit, labelBufferSizeSplit;
highlightParameters( parameterMap, parameterPrefix, geomSplit, symbolSplit, labelSplit, labelFontSplit, labelSizeSplit, labelWeightSplit,
labelColorSplit, labelBufferColorSplit, labelBufferSizeSplit );
if ( geomSplit.isEmpty() || symbolSplit.isEmpty() )
{
return highlightLayers;
}
QString crsString = parameterMap.contains( "CRS" ) ? parameterMap.value( "CRS" ) : parameterMap.value( "SRS" );
int nHighlights = qMin( geomSplit.size(), symbolSplit.size() );
for ( int i = 0; i < nHighlights; ++i )
{
//create geometry
QScopedPointer<QgsGeometry> geom( QgsGeometry::fromWkt( geomSplit.at( i ) ) );
if ( !geom.data() )
{
continue;
}
//create renderer from sld
QString sld = symbolSplit[i];
QDomDocument sldDoc;
if ( !sldDoc.setContent( symbolSplit[i], true ) )
{
continue;
}
QString errorMsg;
QScopedPointer<QgsFeatureRendererV2> renderer( QgsFeatureRendererV2::loadSld( sldDoc.documentElement(), geom.data()->type(), errorMsg ) );
if ( !renderer.data() )
{
continue;
}
//add label settings
QString labelString;
if ( i < labelSplit.size() )
{
labelString = labelSplit.at( i );
}
QScopedPointer<QgsVectorLayer> layer( createHighlightLayer( i, crsString, geom.take(), labelString, labelSizeSplit, labelColorSplit, labelWeightSplit, labelFontSplit,
labelBufferSizeSplit, labelBufferColorSplit ) );
if ( !layer.data() )
{
continue;
}
layer->setRendererV2( renderer.take() );
layerSet.prepend( layer.data()->id() );
highlightLayers.append( layer.data()->id() );
QgsMapLayerRegistry::instance()->addMapLayers( QList<QgsMapLayer *>() << layer.take() );
}
return highlightLayers;
}
QgsVectorLayer* QgsWMSConfigParser::createHighlightLayer( int i, const QString& crsString, QgsGeometry* geom, const QString& labelString, const QStringList& labelSizeSplit, const QStringList& labelColorSplit,
const QStringList& labelWeightSplit, const QStringList& labelFontSplit, const QStringList& labelBufferSizeSplit,
const QStringList& labelBufferColorSplit )
{
if ( !geom )
{
return 0;
}
QGis::GeometryType geomType = geom->type();
QString typeName = QString( QGis::featureType( geom->wkbType() ) ).replace( "WKB", "" );
QString url = typeName + "?crs=" + crsString;
if ( !labelString.isEmpty() )
{
url += "&field=label:string";
if ( geomType == QGis::Polygon )
{
url += "&field=x:double&field=y:double&field=hali:string&field=vali:string";
}
}
QgsVectorLayer* layer = new QgsVectorLayer( url, "highlight_" + QString::number( i ), "memory" );
if ( !layer->isValid() )
{
delete layer;
return 0;
}
QgsFeature fet( layer->pendingFields() );
if ( !labelString.isEmpty() )
{
fet.setAttribute( 0, labelString );
if ( geomType == QGis::Polygon )
{
QgsGeometry* point = geom->pointOnSurface();
if ( point )
{
QgsPoint pt = point->asPoint();
fet.setAttribute( 1, pt.x() );
fet.setAttribute( 2, pt.y() );
fet.setAttribute( 3, "Center" );
fet.setAttribute( 4, "Half" );
}
}
layer->setCustomProperty( "labeling/fieldName", "label" );
layer->setCustomProperty( "labeling/enabled", "true" );
layer->setCustomProperty( "labeling", "pal" );
//give highest priority to highlight layers and make sure the labels are always drawn
layer->setCustomProperty( "labeling/priority", "10" );
layer->setCustomProperty( "labeling/displayAll", "true" );
//fontsize?
if ( i < labelSizeSplit.size() )
{
layer->setCustomProperty( "labeling/fontSize", labelSizeSplit.at( i ) );
}
//font color
if ( i < labelColorSplit.size() )
{
QColor c( labelColorSplit.at( i ) );
layer->setCustomProperty( "labeling/textColorR", c.red() );
layer->setCustomProperty( "labeling/textColorG", c.green() );
layer->setCustomProperty( "labeling/textColorB", c.blue() );
}
//font weight
if ( i < labelWeightSplit.size() )
{
layer->setCustomProperty( "labeling/fontWeight", labelWeightSplit.at( i ) );
}
//font family list
if ( i < labelFontSplit.size() )
{
layer->setCustomProperty( "labeling/fontFamily", labelFontSplit.at( i ) );
}
//buffer
if ( i < labelBufferSizeSplit.size() )
{
layer->setCustomProperty( "labeling/bufferSize", labelBufferSizeSplit.at( i ) );
}
//buffer color
if ( i < labelBufferColorSplit.size() )
{
QColor c( labelBufferColorSplit.at( i ) );
layer->setCustomProperty( "labeling/bufferColorR", c.red() );
layer->setCustomProperty( "labeling/bufferColorG", c.green() );
layer->setCustomProperty( "labeling/bufferColorB", c.blue() );
}
//placement
int placement = 0;
switch ( geomType )
{
case QGis::Point:
placement = 0;
layer->setCustomProperty( "labeling/dist", 2 );
layer->setCustomProperty( "labeling/placementFlags", 0 );
break;
case QGis::Polygon:
layer->setCustomProperty( "labeling/dataDefinedProperty9", 1 );
layer->setCustomProperty( "labeling/dataDefinedProperty10", 2 );
layer->setCustomProperty( "labeling/dataDefinedProperty11", 3 );
layer->setCustomProperty( "labeling/dataDefinedProperty12", 4 );
break;
default:
placement = 2; //parallel placement for line
layer->setCustomProperty( "labeling/dist", 2 );
layer->setCustomProperty( "labeling/placementFlags", 10 );
}
layer->setCustomProperty( "labeling/placement", placement );
}
fet.setGeometry( geom );
layer->dataProvider()->addFeatures( QgsFeatureList() << fet );
return layer;
}
void QgsWMSConfigParser::highlightParameters( const QMap<QString, QString>& parameterMap, const QString& parameterPrefix, QStringList& geom, QStringList& symbol,
QStringList& label, QStringList& labelFont, QStringList& labelSize, QStringList& labelWeight, QStringList& labelColor,
QStringList& labelBufferColor, QStringList& labelBufferSize )
{
QString geomParam = parameterMap.value( parameterPrefix + "HIGHLIGHT_GEOM" );
QString symbolParam = parameterMap.value( parameterPrefix + "HIGHLIGHT_SYMBOL" );
if ( geomParam.isEmpty() || symbolParam.isEmpty() )
{
return;
}
QString labelParam = parameterMap.value( parameterPrefix + "HIGHLIGHT_LABELSTRING" );
QString labelFontParam = parameterMap.value( parameterPrefix + "HIGHLIGHT_LABELFONT" );
QString labelSizeParam = parameterMap.value( parameterPrefix + "HIGHLIGHT_LABELSIZE" );
QString labelWeightParam = parameterMap.value( parameterPrefix + "HIGHLIGHT_LABELWEIGHT" );
QString labelColorParam = parameterMap.value( parameterPrefix + "HIGHLIGHT_LABELCOLOR" );
QString labelBufferColorParam = parameterMap.value( parameterPrefix + "HIGHLIGHT_LABELBUFFERCOLOR" );
QString labelBufferSizeParam = parameterMap.value( parameterPrefix + "HIGHLIGHT_LABELBUFFERSIZE" );
geom = geomParam.split( ";" );
symbol = symbolParam.split( ";" );
label.clear();
labelFont.clear();
labelSize.clear();
labelWeight.clear();
labelColor.clear();
labelBufferColor.clear();
labelBufferSize.clear();
if ( !labelParam.isEmpty() )
{
label = labelParam.split( ";" );
}
if ( !labelFontParam.isEmpty() )
{
labelFont = labelFontParam.split( ";" );
}
if ( !labelSizeParam.isEmpty() )
{
labelSize = labelSizeParam.split( ";" );
}
if ( !labelWeightParam.isEmpty() )
{
labelWeight = labelWeightParam.split( ";" );
}
if ( !labelColorParam.isEmpty() )
{
labelColor = labelColorParam.split( ";" );
}
if ( !labelBufferColorParam.isEmpty() )
{
labelBufferColor = labelBufferColorParam.split( ";" );
}
if ( !labelBufferSizeParam.isEmpty() )
{
labelBufferSize = labelBufferSizeParam.split( ";" );
}
}
void QgsWMSConfigParser::removeHighlightLayers( const QStringList& layerIds )
{
QStringList::const_iterator idIt = layerIds.constBegin();
for ( ; idIt != layerIds.constEnd(); ++idIt )
{
QgsMapLayerRegistry::instance()->removeMapLayers( QStringList() << *idIt );
}
}

View File

@ -113,7 +113,7 @@ class SERVER_EXPORT QgsWMSConfigParser
//printing
/** Creates a print composition, usually for a GetPrint request. Replaces map and label parameters*/
QgsComposition* createPrintComposition( const QString& composerTemplate, QgsMapRenderer* mapRenderer, const QMap< QString, QString >& parameterMap ) const;
QgsComposition* createPrintComposition( const QString& composerTemplate, QgsMapRenderer* mapRenderer, const QMap< QString, QString >& parameterMap, QStringList& highlightLayers ) const;
/** Creates a composition from the project file (probably delegated to the fallback parser)*/
virtual QgsComposition* initComposition( const QString& composerTemplate, QgsMapRenderer* mapRenderer, QList< QgsComposerMap*>& mapList, QList< QgsComposerLegend* >& legendList, QList< QgsComposerLabel* >& labelList, QList<const QgsComposerHtml *>& htmlFrameList ) const = 0;
@ -132,10 +132,25 @@ class SERVER_EXPORT QgsWMSConfigParser
virtual bool useLayerIDs() const = 0;
/** Adds highlight layers to the layer registry and to the layer set. Returns the ids of the newly created layers (for later removal)*/
static QStringList addHighlightLayers( const QMap<QString, QString>& parameterMap, QStringList& layerSet, const QString& parameterPrefix = QString() );
static void removeHighlightLayers( const QStringList& layerIds );
#if 0
/** List of GML datasets passed outside SLD (e.g. in a SOAP request). Key of the map is the layer name*/
QMap<QString, QDomDocument*> mExternalGMLDatasets;
#endif //0
private:
//helper methods for 'addHighlightLayers'
static void highlightParameters( const QMap<QString, QString>& parameterMap, const QString &parameterPrefix, QStringList& geom, QStringList& symbol, QStringList& label,
QStringList& labelFont, QStringList& labelSize, QStringList& labelWeight, QStringList& labelColor,
QStringList& labelBufferColor, QStringList &labelBufferSize );
static QgsVectorLayer* createHighlightLayer( int i, const QString& crsString, QgsGeometry* geom, const QString& labelString, const QStringList& labelSizeSplit, const QStringList& labelColorSplit,
const QStringList& labelWeightSplit, const QStringList& labelFontSplit, const QStringList& labelBufferSizeSplit,
const QStringList& labelBufferColorSplit );
};
#endif // QGSWMSCONFIGPARSER_H

View File

@ -1282,12 +1282,13 @@ QByteArray* QgsWMSServer::getPrint( const QString& formatString )
applyOpacities( layersList, bkVectorRenderers, bkRasterRenderers, labelTransparencies, labelBufferTransparencies );
QgsComposition* c = mConfigParser->createPrintComposition( mParameters[ "TEMPLATE" ], mMapRenderer, QMap<QString, QString>( mParameters ) );
QStringList highlightLayers;
QgsComposition* c = mConfigParser->createPrintComposition( mParameters[ "TEMPLATE" ], mMapRenderer, QMap<QString, QString>( mParameters ), highlightLayers );
if ( !c )
{
restoreOpacities( bkVectorRenderers, bkRasterRenderers, labelTransparencies, labelBufferTransparencies );
clearFeatureSelections( selectedLayerIdList );
QgsWMSConfigParser::removeHighlightLayers( highlightLayers );
return nullptr;
}
@ -1353,6 +1354,7 @@ QByteArray* QgsWMSServer::getPrint( const QString& formatString )
restoreOpacities( bkVectorRenderers, bkRasterRenderers, labelTransparencies, labelBufferTransparencies );
clearFeatureSelections( selectedLayerIdList );
QgsWMSConfigParser::removeHighlightLayers( highlightLayers );
delete c;
return ba;
@ -1388,6 +1390,10 @@ QImage* QgsWMSServer::getMap( HitTest* hitTest )
QPainter thePainter( theImage );
thePainter.setRenderHint( QPainter::Antialiasing ); //make it look nicer
QStringList layerSet = mMapRenderer->layerSet();
QStringList highlightLayers = QgsWMSConfigParser::addHighlightLayers( mParameters, layerSet );
mMapRenderer->setLayerSet( layerSet );
#ifdef HAVE_SERVER_PYTHON_PLUGINS
Q_FOREACH ( QgsMapLayer *layer, QgsMapLayerRegistry::instance()->mapLayers() )
{
@ -1432,6 +1438,7 @@ QImage* QgsWMSServer::getMap( HitTest* hitTest )
restoreOpacities( bkVectorRenderers, bkRasterRenderers, labelTransparencies, labelBufferTransparencies );
clearFeatureSelections( selectedLayerIdList );
QgsWMSConfigParser::removeHighlightLayers( highlightLayers );
// QgsMessageLog::logMessage( "clearing filters" );
if ( !hitTest )