mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-28 00:05:04 -04:00
1989 lines
67 KiB
C++
1989 lines
67 KiB
C++
/***************************************************************************
|
|
qgssldparser.h
|
|
Creates a set of maplayers from an sld
|
|
-------------------
|
|
begin : May 07, 2006
|
|
copyright : (C) 2006 by Marco Hugentobler & Ionut Iosifescu Enescu
|
|
email : marco dot hugentobler at karto dot baug dot ethz dot ch
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "qgssldparser.h"
|
|
#include "qgsapplication.h"
|
|
#include "qgscoordinatetransform.h"
|
|
#include "qgsftptransaction.h"
|
|
#include "qgshttptransaction.h"
|
|
#include "qgsrendererv2.h"
|
|
#include "qgssinglesymbolrendererv2.h"
|
|
#include "qgssymbolv2.h"
|
|
#include "qgsvectordataprovider.h"
|
|
#include "qgsvectorlayer.h"
|
|
#include "qgsmapserviceexception.h"
|
|
#include "qgslogger.h"
|
|
#include "qgsmslayercache.h"
|
|
#include "qgsmsutils.h"
|
|
#include "qgsrasterlayer.h"
|
|
#include "qgscolorrampshader.h"
|
|
#include "qgscoordinatereferencesystem.h"
|
|
#include "qgslabelattributes.h"
|
|
|
|
#include <QDomDocument>
|
|
#include <QDomElement>
|
|
#include <QBrush>
|
|
#include <QDir>
|
|
#include <QFileInfo>
|
|
#include <QPen>
|
|
#include <QTextStream>
|
|
#include <QVector>
|
|
#include <float.h>
|
|
#include <time.h>
|
|
#include "qgslabel.h"
|
|
#include <stdlib.h>
|
|
#include <fcgi_stdio.h>
|
|
|
|
|
|
//layer builders
|
|
#include "qgshostedrdsbuilder.h"
|
|
#include "qgshostedvdsbuilder.h"
|
|
#include "qgsremotedatasourcebuilder.h"
|
|
#include "qgsremoteowsbuilder.h"
|
|
#include "qgssentdatasourcebuilder.h"
|
|
|
|
#ifdef DIAGRAMSERVER
|
|
#include "qgsdiagramoverlay.h"
|
|
#include "qgsbardiagramfactory.h"
|
|
#include "qgspiediagramfactory.h"
|
|
#include "qgsdiagramrenderer.h"
|
|
#include "qgssvgdiagramfactory.h"
|
|
#endif //DIAGRAMSERVER
|
|
|
|
//for contours
|
|
#include "gdal_alg.h"
|
|
#include "ogr_srs_api.h"
|
|
#include "ogr_api.h"
|
|
|
|
//for raster interpolation
|
|
#include "qgsinterpolationlayerbuilder.h"
|
|
#include "qgsgridfilewriter.h"
|
|
#include "qgsidwinterpolator.h"
|
|
#include "qgstininterpolator.h"
|
|
|
|
#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800
|
|
#define TO8(x) (x).toUtf8().constData()
|
|
#else
|
|
#define TO8(x) (x).toLocal8Bit().constData()
|
|
#endif
|
|
|
|
QgsSLDParser::QgsSLDParser( QDomDocument* doc ): QgsConfigParser(), mXMLDoc( doc )
|
|
{
|
|
mSLDNamespace = "http://www.opengis.net/sld";
|
|
if ( doc->firstChild().namespaceURI() != "http://www.opengis.net/sld" && doc->firstChild().nodeName().startsWith( "sld:" ) )
|
|
{
|
|
mSLDNamespace = "";
|
|
}
|
|
|
|
//set output units
|
|
if ( mXMLDoc )
|
|
{
|
|
//first search attribute "units" in <StyledLayerDescriptor> element
|
|
QDomElement sldElement = mXMLDoc->documentElement();
|
|
if ( !sldElement.isNull() )
|
|
{
|
|
QString unitString = sldElement.attribute( "units" );
|
|
if ( !unitString.isEmpty() )
|
|
{
|
|
if ( unitString == "mm" )
|
|
{
|
|
mOutputUnits = QgsMapRenderer::Millimeters;
|
|
}
|
|
else if ( unitString == "pixel" )
|
|
{
|
|
mOutputUnits = QgsMapRenderer::Pixels;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
QgsSLDParser::QgsSLDParser(): mXMLDoc( 0 )
|
|
{
|
|
mSLDNamespace = "http://www.opengis.net/sld";
|
|
}
|
|
|
|
QgsSLDParser::~QgsSLDParser()
|
|
{
|
|
delete mXMLDoc;
|
|
}
|
|
|
|
int QgsSLDParser::numberOfLayers() const
|
|
{
|
|
if ( !mXMLDoc )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
QDomElement sldElem = mXMLDoc->documentElement().toElement();
|
|
if ( sldElem.isNull() )
|
|
{
|
|
return 0;
|
|
}
|
|
QDomNodeList userLayerList = sldElem.elementsByTagName( "UserLayer" );
|
|
QDomNodeList namedLayerList = sldElem.elementsByTagName( "NamedLayer" );
|
|
return ( userLayerList.size() + namedLayerList.size() );
|
|
}
|
|
|
|
void QgsSLDParser::layersAndStylesCapabilities( QDomElement& parentElement, QDomDocument& doc, const QString& version, bool fullProjectSettings ) const
|
|
{
|
|
Q_UNUSED( version );
|
|
Q_UNUSED( fullProjectSettings );
|
|
//iterate over all <UserLayer> nodes
|
|
if ( mXMLDoc )
|
|
{
|
|
QDomNode sldNode = mXMLDoc->documentElement();
|
|
if ( !sldNode.isNull() )
|
|
{
|
|
//create wgs84 to reproject the layer bounding boxes
|
|
//QgsCoordinateReferenceSystem wgs84;
|
|
//wgs84.createFromEpsg(4326);
|
|
|
|
QDomNodeList layerNodeList = sldNode.toElement().elementsByTagName( "UserLayer" );
|
|
for ( int i = 0; i < layerNodeList.size(); ++i )
|
|
{
|
|
QDomElement layerElement = doc.createElement( "Layer" );
|
|
layerElement.setAttribute( "queryable", "1" ); //support GetFeatureInfo for all layers
|
|
parentElement.appendChild( layerElement );
|
|
|
|
//add name
|
|
QDomNodeList nameList = layerNodeList.item( i ).toElement().elementsByTagName( "Name" );
|
|
if ( nameList.size() > 0 )
|
|
{
|
|
//layer name
|
|
QDomElement layerNameElement = doc.createElement( "Name" );
|
|
QDomText layerNameText = doc.createTextNode( nameList.item( 0 ).toElement().text() );
|
|
layerNameElement.appendChild( layerNameText );
|
|
layerElement.appendChild( layerNameElement );
|
|
}
|
|
|
|
//add title
|
|
QDomNodeList titleList = layerNodeList.item( i ).toElement().elementsByTagName( "Title" );
|
|
if ( titleList.size() > 0 )
|
|
{
|
|
QDomElement layerTitleElement = doc.createElement( "Title" );
|
|
QDomText layerTitleText = doc.createTextNode( titleList.item( 0 ).toElement().text() );
|
|
layerTitleElement.appendChild( layerTitleText );
|
|
layerElement.appendChild( layerTitleElement );
|
|
}
|
|
//add abstract
|
|
QDomNodeList abstractList = layerNodeList.item( i ).toElement().elementsByTagName( "Abstract" );
|
|
if ( abstractList.size() > 0 )
|
|
{
|
|
QDomElement layerAbstractElement = doc.createElement( "Abstract" );
|
|
QDomText layerAbstractText = doc.createTextNode( abstractList.item( 0 ).toElement().text() );
|
|
layerAbstractElement.appendChild( layerAbstractText );
|
|
layerElement.appendChild( layerAbstractElement );
|
|
}
|
|
|
|
|
|
//get QgsMapLayer object to add Ex_GeographicalBoundingBox, Bounding Box
|
|
QList<QgsMapLayer*> layerList = mapLayerFromStyle( nameList.item( 0 ).toElement().text(), "" );
|
|
if ( layerList.size() < 1 )//error while generating the layer
|
|
{
|
|
QgsDebugMsg( "Error, no maplayer in layer list" );
|
|
continue;
|
|
}
|
|
|
|
//get only the first layer since we don't want to have the other ones in the capabilities document
|
|
QgsMapLayer* theMapLayer = layerList.at( 0 );
|
|
if ( !theMapLayer )//error while generating the layer
|
|
{
|
|
QgsDebugMsg( "Error, QgsMapLayer object is 0" );
|
|
continue;
|
|
}
|
|
|
|
//append geographic bbox and the CRS elements
|
|
QStringList crsNumbers = createCRSListForLayer( theMapLayer );
|
|
appendCRSElementsToLayer( layerElement, doc, crsNumbers );
|
|
appendLayerBoundingBoxes( layerElement, doc, theMapLayer->extent(), theMapLayer->crs() );
|
|
|
|
//iterate over all <UserStyle> nodes within a user layer
|
|
QDomNodeList userStyleList = layerNodeList.item( i ).toElement().elementsByTagName( "UserStyle" );
|
|
for ( int j = 0; j < userStyleList.size(); ++j )
|
|
{
|
|
QDomElement styleElement = doc.createElement( "Style" );
|
|
layerElement.appendChild( styleElement );
|
|
//Name
|
|
QDomNodeList nameList = userStyleList.item( j ).toElement().elementsByTagName( "Name" );
|
|
if ( nameList.size() > 0 )
|
|
{
|
|
QDomElement styleNameElement = doc.createElement( "Name" );
|
|
QDomText styleNameText = doc.createTextNode( nameList.item( 0 ).toElement().text() );
|
|
styleNameElement.appendChild( styleNameText );
|
|
styleElement.appendChild( styleNameElement );
|
|
|
|
QDomElement styleTitleElement = doc.createElement( "Title" );
|
|
QDomText styleTitleText = doc.createTextNode( nameList.item( 0 ).toElement().text() );
|
|
styleTitleElement.appendChild( styleTitleText );
|
|
styleElement.appendChild( styleTitleElement );
|
|
}
|
|
//Title
|
|
QDomNodeList titleList = userStyleList.item( j ).toElement().elementsByTagName( "Title" );
|
|
if ( titleList.size() > 0 )
|
|
{
|
|
QDomElement styleTitleElement = doc.createElement( "Title" );
|
|
QDomText styleTitleText = doc.createTextNode( titleList.item( 0 ).toElement().text() );
|
|
styleTitleElement.appendChild( styleTitleText );
|
|
styleElement.appendChild( styleTitleElement );
|
|
}
|
|
//Abstract
|
|
QDomNodeList abstractList = userStyleList.item( j ).toElement().elementsByTagName( "Abstract" );
|
|
if ( abstractList.size() > 0 )
|
|
{
|
|
QDomElement styleAbstractElement = doc.createElement( "Abstract" );
|
|
QDomText styleAbstractText = doc.createTextNode( abstractList.item( 0 ).toElement().text() );
|
|
styleAbstractElement.appendChild( styleAbstractText );
|
|
styleElement.appendChild( styleAbstractElement );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
QList<QgsMapLayer*> QgsSLDParser::mapLayerFromStyle( const QString& layerName, const QString& styleName, bool useCache ) const
|
|
{
|
|
QList<QgsMapLayer*> fallbackLayerList;
|
|
QList<QgsMapLayer*> resultList;
|
|
|
|
//first check if this layer is a named layer with a user style
|
|
QList<QDomElement> namedLayerElemList = findNamedLayerElements( layerName );
|
|
for ( int i = 0; i < namedLayerElemList.size(); ++i )
|
|
{
|
|
QDomElement userStyleElement = findUserStyleElement( namedLayerElemList[i], styleName );
|
|
if ( !userStyleElement.isNull() )
|
|
{
|
|
fallbackLayerList = mFallbackParser->mapLayerFromStyle( layerName, "", false );
|
|
if ( fallbackLayerList.size() > 0 )
|
|
{
|
|
QgsVectorLayer* v = dynamic_cast<QgsVectorLayer*>( fallbackLayerList.at( 0 ) );
|
|
if ( v )
|
|
{
|
|
QgsFeatureRendererV2* r = rendererFromUserStyle( userStyleElement, v );
|
|
v->setRendererV2( r );
|
|
labelSettingsFromUserStyle( userStyleElement, v );
|
|
#ifdef DIAGRAMSERVER
|
|
overlaysFromUserStyle( userStyleElement, v );
|
|
#endif //DIAGRAMSERVER
|
|
setOpacityForLayer( namedLayerElemList[i], v );
|
|
|
|
resultList.push_back( v );
|
|
return resultList;
|
|
}
|
|
else
|
|
{
|
|
QgsRasterLayer* r = dynamic_cast<QgsRasterLayer*>( fallbackLayerList.at( 0 ) ); //a raster layer?
|
|
if ( r )
|
|
{
|
|
rasterSymbologyFromUserStyle( userStyleElement, r );
|
|
|
|
setOpacityForLayer( namedLayerElemList[i], r );
|
|
|
|
//Using a contour symbolizer, there may be a raster and a vector layer
|
|
QgsVectorLayer* v = contourLayerFromRaster( userStyleElement, r );
|
|
if ( v )
|
|
{
|
|
resultList.push_back( v ); //contour layer must be added before raster
|
|
mLayersToRemove.push_back( v ); //don't cache contour layers at the moment
|
|
}
|
|
resultList.push_back( r );
|
|
return resultList;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
QDomElement userLayerElement = findUserLayerElement( layerName );
|
|
|
|
if ( userLayerElement.isNull() )
|
|
{
|
|
//maybe named layer and named style is defined in the fallback SLD?
|
|
if ( mFallbackParser )
|
|
{
|
|
resultList = mFallbackParser->mapLayerFromStyle( layerName, styleName, useCache );
|
|
}
|
|
|
|
QList<QgsMapLayer*>::iterator it = resultList.begin();
|
|
for ( ; it != resultList.end(); ++it )
|
|
{
|
|
setOpacityForLayer( userLayerElement, *it );
|
|
}
|
|
|
|
return resultList;
|
|
}
|
|
|
|
QDomElement userStyleElement = findUserStyleElement( userLayerElement, styleName );
|
|
|
|
QgsMapLayer* theMapLayer = mapLayerFromUserLayer( userLayerElement, layerName, useCache );
|
|
if ( !theMapLayer )
|
|
{
|
|
return resultList;
|
|
}
|
|
|
|
QgsFeatureRendererV2* theRenderer = 0;
|
|
|
|
QgsVectorLayer* theVectorLayer = dynamic_cast<QgsVectorLayer*>( theMapLayer );
|
|
if ( !theVectorLayer )
|
|
{
|
|
//a raster layer
|
|
QgsRasterLayer* theRasterLayer = dynamic_cast<QgsRasterLayer*>( theMapLayer );
|
|
if ( theRasterLayer )
|
|
{
|
|
QgsDebugMsg( "Layer is a rasterLayer" );
|
|
if ( !userStyleElement.isNull() )
|
|
{
|
|
QgsDebugMsg( "Trying to add raster symbology" );
|
|
rasterSymbologyFromUserStyle( userStyleElement, theRasterLayer );
|
|
//todo: possibility to have vector layer or raster layer
|
|
QgsDebugMsg( "Trying to find contour symbolizer" );
|
|
QgsVectorLayer* v = contourLayerFromRaster( userStyleElement, theRasterLayer );
|
|
if ( v )
|
|
{
|
|
QgsDebugMsg( "Returning vector layer" );
|
|
resultList.push_back( v );
|
|
mLayersToRemove.push_back( v );
|
|
}
|
|
}
|
|
setOpacityForLayer( userLayerElement, theMapLayer );
|
|
resultList.push_back( theMapLayer );
|
|
|
|
return resultList;
|
|
}
|
|
}
|
|
|
|
if ( userStyleElement.isNull() )//apply a default style
|
|
{
|
|
QgsSymbolV2* symbol = QgsSymbolV2::defaultSymbol( theVectorLayer->geometryType() );
|
|
theRenderer = new QgsSingleSymbolRendererV2( symbol );
|
|
}
|
|
else
|
|
{
|
|
QgsDebugMsg( "Trying to get a renderer from the user style" );
|
|
theRenderer = rendererFromUserStyle( userStyleElement, theVectorLayer );
|
|
//apply labels if <TextSymbolizer> tag is present
|
|
labelSettingsFromUserStyle( userStyleElement, theVectorLayer );
|
|
#ifdef DIAGRAMSERVER
|
|
//apply any vector overlays
|
|
QgsDebugMsg( "Trying to get overlays from user style" );
|
|
overlaysFromUserStyle( userStyleElement, theVectorLayer );
|
|
#endif //DIAGRAMSERVER
|
|
}
|
|
|
|
if ( !theRenderer )
|
|
{
|
|
QgsDebugMsg( "Error, could not create a renderer" );
|
|
delete theVectorLayer;
|
|
return resultList;
|
|
}
|
|
theVectorLayer->setRendererV2( theRenderer );
|
|
QgsDebugMsg( "Returning the vectorlayer" );
|
|
setOpacityForLayer( userLayerElement, theVectorLayer );
|
|
resultList.push_back( theVectorLayer );
|
|
return resultList;
|
|
}
|
|
|
|
QgsFeatureRendererV2* QgsSLDParser::rendererFromUserStyle( const QDomElement& userStyleElement, QgsVectorLayer* vec ) const
|
|
{
|
|
if ( !vec || userStyleElement.isNull() )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
QgsDebugMsg( "Entering" );
|
|
|
|
QString errorMessage;
|
|
QgsFeatureRendererV2* renderer = QgsFeatureRendererV2::loadSld( userStyleElement.parentNode(), vec->geometryType(), errorMessage );
|
|
if ( !renderer )
|
|
{
|
|
throw QgsMapServiceException( "SLD error", errorMessage );
|
|
}
|
|
return renderer;
|
|
}
|
|
|
|
bool QgsSLDParser::rasterSymbologyFromUserStyle( const QDomElement& userStyleElement, QgsRasterLayer* r ) const
|
|
{
|
|
return false;
|
|
#if 0 //needs to be fixed
|
|
QgsDebugMsg( "Entering" );
|
|
if ( !r )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//search raster symbolizer
|
|
QDomNodeList rasterSymbolizerList = userStyleElement.elementsByTagName( "RasterSymbolizer" );
|
|
if ( rasterSymbolizerList.size() < 1 )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
QDomElement rasterSymbolizerElem = rasterSymbolizerList.at( 0 ).toElement();
|
|
|
|
//search colormap and entries
|
|
QDomNodeList colorMapList = rasterSymbolizerElem.elementsByTagName( "ColorMap" );
|
|
if ( colorMapList.size() < 1 )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
QDomElement colorMapElem = colorMapList.at( 0 ).toElement();
|
|
|
|
//search for color map entries
|
|
r->setColorShadingAlgorithm( QgsRasterLayer::ColorRampShader );
|
|
QgsColorRampShader* myRasterShaderFunction = ( QgsColorRampShader* )r->rasterShader()->rasterShaderFunction();
|
|
QList<QgsColorRampShader::ColorRampItem> colorRampItems;
|
|
|
|
QDomNodeList colorMapEntryList = colorMapElem.elementsByTagName( "ColorMapEntry" );
|
|
QDomElement currentColorMapEntryElem;
|
|
bool conversion;
|
|
int red, green, blue;
|
|
|
|
for ( int i = 0; i < colorMapEntryList.size(); ++i )
|
|
{
|
|
currentColorMapEntryElem = colorMapEntryList.at( i ).toElement();
|
|
QgsColorRampShader::ColorRampItem myNewColorRampItem;
|
|
QString color = currentColorMapEntryElem.attribute( "color" );
|
|
if ( color.length() != 7 ) //color string must be in the form #ffffff
|
|
{
|
|
continue;
|
|
}
|
|
red = color.mid( 1, 2 ).toInt( &conversion, 16 );
|
|
if ( !conversion )
|
|
{
|
|
red = 0;
|
|
}
|
|
green = color.mid( 3, 2 ).toInt( &conversion, 16 );
|
|
if ( !conversion )
|
|
{
|
|
green = 0;
|
|
}
|
|
blue = color.mid( 5, 2 ).toInt( &conversion, 16 );
|
|
if ( !conversion )
|
|
{
|
|
blue = 0;
|
|
}
|
|
myNewColorRampItem.color = QColor( red, green, blue );
|
|
QString value = currentColorMapEntryElem.attribute( "quantity" );
|
|
myNewColorRampItem.value = value.toDouble();
|
|
QgsDebugMsg( "Adding colormap entry" );
|
|
colorRampItems.push_back( myNewColorRampItem );
|
|
}
|
|
|
|
myRasterShaderFunction->setColorRampItemList( colorRampItems );
|
|
|
|
//linear interpolation or discrete classification
|
|
QString interpolation = colorMapElem.attribute( "interpolation" );
|
|
if ( interpolation == "linear" )
|
|
{
|
|
myRasterShaderFunction->setColorRampType( QgsColorRampShader::INTERPOLATED );
|
|
}
|
|
else if ( interpolation == "discrete" )
|
|
{
|
|
myRasterShaderFunction->setColorRampType( QgsColorRampShader::DISCRETE );
|
|
}
|
|
|
|
//QgsDebugMsg("Setting drawing style");
|
|
r->setDrawingStyle( QgsRasterLayer::SingleBandPseudoColor );
|
|
|
|
//set pseudo color mode
|
|
return true;
|
|
#else
|
|
Q_UNUSED( userStyleElement );
|
|
Q_UNUSED( r );
|
|
#endif //0
|
|
}
|
|
|
|
// ---------------labelSettingsFromUserStyle-----------------------
|
|
|
|
bool QgsSLDParser::labelSettingsFromUserStyle( const QDomElement& userStyleElement, QgsVectorLayer* vec ) const
|
|
{
|
|
if ( userStyleElement.isNull() || !vec )
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
vec->enableLabels( false );
|
|
QDomNodeList featureTypeList = userStyleElement.elementsByTagName( "FeatureTypeStyle" );
|
|
if ( featureTypeList.size() > 0 )
|
|
{
|
|
//QGIS WMS server only supports one featureTypeStyle per layer
|
|
QDomNodeList ruleNodeList = featureTypeList.item( 0 ).toElement().elementsByTagName( "Rule" );
|
|
// if there are rule elements:
|
|
if ( ruleNodeList.size() > 0 )
|
|
{
|
|
// rule element
|
|
QDomElement ruleElement = ruleNodeList.item( ruleNodeList.size() - 1 ).toElement();
|
|
//find <TextSymbolizer>.
|
|
//Unfortunately, QGIS does not support having different labels for different classifications.
|
|
//Therefore we take the last text symbolizer for all features
|
|
QDomNodeList textSymbolizerList = ruleElement.elementsByTagName( "TextSymbolizer" );
|
|
// if there are textSymbolizers
|
|
if ( textSymbolizerList.size() > 0 )
|
|
{
|
|
int opacity = 255;
|
|
int polyColorRed = 0;
|
|
int polyColorGreen = 0;
|
|
int polyColorBlue = 0;
|
|
QString elemText;
|
|
QString fontfamily = QString( "Helvetica" );
|
|
QString fontstyle = QString( "Normal" );
|
|
int fontsize = 14;
|
|
QString fontweight = QString( "Normal" );
|
|
QString fontunderline = QString( "Normal" );
|
|
bool success = false;
|
|
|
|
QDomElement textSymbolizerElement = textSymbolizerList.item( textSymbolizerList.size() - 1 ).toElement();
|
|
// if there is a viable text textSymbolizerElement
|
|
if ( !textSymbolizerElement.isNull() )
|
|
{
|
|
QgsLabelAttributes * myLabelAttributes = vec->label()->labelAttributes();
|
|
//element <Label> contains the attribute name
|
|
QDomNodeList labelNodeList = textSymbolizerElement.elementsByTagName( "Label" );
|
|
// if a viable label element is provided
|
|
if ( labelNodeList.size() > 0 )
|
|
{
|
|
QDomElement labelElement = labelNodeList.item( 0 ).toElement();
|
|
//we need the text of an <ogc:PropertyName> element
|
|
QDomNodeList propertyNameList = labelElement.elementsByTagName( "PropertyName" );
|
|
if ( propertyNameList.size() > 0 )
|
|
{
|
|
vec->enableLabels( true );
|
|
QDomElement propertyNameElement = propertyNameList.item( 0 ).toElement();
|
|
QString labelAttribute = propertyNameElement.text();
|
|
vec->label()->setLabelField( QgsLabel::Text, vec->dataProvider()->fieldNameIndex( labelAttribute ) );
|
|
|
|
// Iterate through each of CssParameter from the sld:font, sld:fill, sld:halo
|
|
QDomNodeList labelFontElementList = textSymbolizerElement.elementsByTagName( "Font" );
|
|
QDomNodeList labelFillElementList = textSymbolizerElement.elementsByTagName( "Fill" );
|
|
QDomNodeList labelBufferElementList = textSymbolizerElement.elementsByTagName( "Halo" );
|
|
QDomNodeList labelPlacementElementList = textSymbolizerElement.elementsByTagName( "LabelPlacement" );
|
|
// Iterate through sld:font
|
|
if (( labelFontElementList.size() > 0 ) )
|
|
{
|
|
if ( !labelFontElementList.item( 0 ).toElement().isNull() )
|
|
{
|
|
QDomNodeList cssNodes = labelFontElementList.item( 0 ).toElement().elementsByTagName( "CssParameter" );
|
|
QString cssName;
|
|
QDomElement currentElement;
|
|
QgsDebugMsg( "Number of Css Properties: " + QString::number( cssNodes.size() ) );
|
|
for ( int i = 0; i < cssNodes.size(); ++i )
|
|
{
|
|
currentElement = cssNodes.item( i ).toElement();
|
|
if ( currentElement.isNull() )
|
|
{
|
|
continue;
|
|
}
|
|
QString elemText = currentElement.text();
|
|
|
|
//switch depending on attribute 'name'
|
|
cssName = currentElement.attribute( "name", "not_found" );
|
|
QgsDebugMsg( "property " + QString::number( i ) + ": " + cssName + " " + elemText );
|
|
if ( cssName != "not_found" )
|
|
{
|
|
if ( cssName == "font-family" )
|
|
{
|
|
QgsDebugMsg( cssName + " " + elemText );
|
|
fontfamily = elemText;
|
|
}
|
|
else if ( cssName == "font-style" )
|
|
{
|
|
QgsDebugMsg( cssName + " " + elemText );
|
|
fontstyle = elemText;
|
|
}
|
|
else if ( cssName == "font-size" )
|
|
{
|
|
QgsDebugMsg( cssName + " " + elemText );
|
|
success = false;
|
|
fontsize = elemText.toInt( &success );
|
|
if ( !success )
|
|
{
|
|
fontsize = 12;
|
|
}
|
|
|
|
}
|
|
else if ( cssName == "font-weight" )
|
|
{
|
|
QgsDebugMsg( cssName + " " + elemText );
|
|
fontweight = elemText;
|
|
}
|
|
else if ( cssName == "font-underline" )
|
|
{
|
|
QgsDebugMsg( cssName + " " + elemText );
|
|
fontunderline = elemText;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
// Iterate through sld:fill
|
|
if (( labelFillElementList.size() > 0 ) )
|
|
{
|
|
if ( !labelFillElementList.item( 0 ).toElement().isNull() )
|
|
{
|
|
QDomNodeList cssNodes = labelFillElementList.item( 0 ).toElement().elementsByTagName( "CssParameter" );
|
|
QString cssName;
|
|
QDomElement currentElement;
|
|
QgsDebugMsg( "Number of Css Properties: " + QString::number( cssNodes.size() ) );
|
|
for ( int i = 0; i < cssNodes.size(); ++i )
|
|
{
|
|
currentElement = cssNodes.item( i ).toElement();
|
|
if ( currentElement.isNull() )
|
|
{
|
|
continue;
|
|
}
|
|
QString elemText = currentElement.text();
|
|
|
|
//switch depending on attribute 'name'
|
|
cssName = currentElement.attribute( "name", "not_found" );
|
|
QgsDebugMsg( "property " + QString::number( i ) + ": " + cssName + " " + elemText );
|
|
if ( cssName != "not_found" )
|
|
{
|
|
if ( cssName == "fill" )
|
|
{
|
|
QgsDebugMsg( cssName + " " + elemText );
|
|
//accept input in the form of #ff0000
|
|
if ( elemText.length() == 7 )
|
|
{
|
|
bool success;
|
|
polyColorRed = elemText.mid( 1, 2 ).toInt( &success, 16 );
|
|
if ( !success )
|
|
{
|
|
polyColorRed = 0;
|
|
}
|
|
polyColorGreen = elemText.mid( 3, 2 ).toInt( &success, 16 );
|
|
if ( !success )
|
|
{
|
|
polyColorGreen = 0;
|
|
}
|
|
polyColorBlue = elemText.mid( 5, 2 ).toInt( &success, 16 );
|
|
if ( !success )
|
|
{
|
|
polyColorBlue = 0;
|
|
}
|
|
}
|
|
}
|
|
else if ( cssName == "fill-opacity" )
|
|
{
|
|
QgsDebugMsg( cssName + " " + elemText );
|
|
bool success;
|
|
double op = elemText.toDouble( &success );
|
|
if ( success )
|
|
{
|
|
if ( op > 1.0 )
|
|
{
|
|
opacity = 255;
|
|
}
|
|
else if ( op < 0.0 )
|
|
{
|
|
opacity = 0;
|
|
}
|
|
else
|
|
{
|
|
opacity = ( int )( 255 * op );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
myLabelAttributes->setSize( fontsize, QgsLabelAttributes::PointUnits );
|
|
myLabelAttributes->setFamily( fontfamily );
|
|
myLabelAttributes->setColor( QColor( polyColorRed, polyColorGreen, polyColorBlue, opacity ) );
|
|
if (( fontstyle == "italic" ) || ( fontstyle == "Italic" ) )
|
|
{
|
|
myLabelAttributes->setItalic( true );
|
|
}
|
|
if (( fontweight == "bold" ) || ( fontweight == "Bold" ) )
|
|
{
|
|
myLabelAttributes->setBold( true );
|
|
}
|
|
if (( fontunderline == "underline" ) || ( fontunderline == "Underline" ) )
|
|
{
|
|
myLabelAttributes->setUnderline( true );
|
|
}
|
|
// set label buffer(sld:halo)
|
|
|
|
if (( labelBufferElementList.size() > 0 ) )
|
|
{
|
|
if ( !labelBufferElementList.item( 0 ).toElement().isNull() )
|
|
{
|
|
QDomNodeList cssNodes = labelBufferElementList.item( 0 ).toElement().elementsByTagName( "CssParameter" );
|
|
QString cssName;
|
|
QDomElement currentElement;
|
|
QgsDebugMsg( "Number of Css Properties: " + QString::number( cssNodes.size() ) );
|
|
for ( int i = 0; i < cssNodes.size(); ++i )
|
|
{
|
|
currentElement = cssNodes.item( i ).toElement();
|
|
if ( currentElement.isNull() )
|
|
{
|
|
continue;
|
|
}
|
|
QString elemText = currentElement.text();
|
|
|
|
//switch depending on attribute 'name'
|
|
cssName = currentElement.attribute( "name", "not_found" );
|
|
QgsDebugMsg( "property " + QString::number( i ) + ": " + cssName + " " + elemText );
|
|
if ( cssName != "not_found" )
|
|
{
|
|
if ( cssName == "fill" )
|
|
{
|
|
QgsDebugMsg( cssName + " " + elemText );
|
|
//accept input in the form of #ff0000
|
|
if ( elemText.length() == 7 )
|
|
{
|
|
bool success;
|
|
polyColorRed = elemText.mid( 1, 2 ).toInt( &success, 16 );
|
|
if ( !success )
|
|
{
|
|
polyColorRed = 255;
|
|
}
|
|
polyColorGreen = elemText.mid( 3, 2 ).toInt( &success, 16 );
|
|
if ( !success )
|
|
{
|
|
polyColorGreen = 255;
|
|
}
|
|
polyColorBlue = elemText.mid( 5, 2 ).toInt( &success, 16 );
|
|
if ( !success )
|
|
{
|
|
polyColorBlue = 255;
|
|
}
|
|
}
|
|
}
|
|
else if ( cssName == "fill-opacity" )
|
|
{
|
|
QgsDebugMsg( cssName + " " + elemText );
|
|
bool success;
|
|
double op = elemText.toDouble( &success );
|
|
if ( success )
|
|
{
|
|
if ( op > 1.0 )
|
|
{
|
|
opacity = 255;
|
|
}
|
|
else if ( op < 0.0 )
|
|
{
|
|
opacity = 0;
|
|
}
|
|
else
|
|
{
|
|
opacity = ( int )( 255 * op );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//QgsMapServerLogger::instance()->printMessage("radius " + QString::number(radius));
|
|
myLabelAttributes->setBufferEnabled( true );
|
|
myLabelAttributes->setBufferColor( QColor( polyColorRed, polyColorGreen, polyColorBlue, opacity ) );
|
|
|
|
#if 0
|
|
double radius = 5.0;
|
|
QDomElement radiusElement = labelBufferElementList.item( 0 ).toElement().elementsByTagName( "Radius" ).item( 0 ).toElement();
|
|
if ( !radiusElement.isNull() )
|
|
{
|
|
bool success = false;
|
|
radius = radiusElement.text().toDouble( &success );
|
|
if ( !success )
|
|
{
|
|
radius = 5.0;
|
|
}
|
|
}
|
|
myLabelAttributes->setBufferSize( radius, QgsLabelAttributes::PointUnits );
|
|
#endif
|
|
|
|
// ******** BUG ************ see why setting buffersize dows not work (is a problem in QGIS vector layer rendering)
|
|
|
|
}
|
|
}
|
|
|
|
// label placement
|
|
if (( labelPlacementElementList.size() > 0 ) )
|
|
{
|
|
if ( !labelPlacementElementList.item( 0 ).toElement().isNull() )
|
|
{
|
|
double displacementX = 0.0;
|
|
double displacementY = 0.0;
|
|
double rotationAngle = 0.0;
|
|
|
|
QDomElement pointPlacementElement = labelPlacementElementList.item( 0 ).toElement().elementsByTagName( "PointPlacement" ).item( 0 ).toElement();
|
|
if ( !pointPlacementElement.isNull() )
|
|
{
|
|
bool success = false;
|
|
rotationAngle = pointPlacementElement.elementsByTagName( "Rotation" ).item( 0 ).toElement().text().toDouble( &success );
|
|
if ( !success )
|
|
{
|
|
rotationAngle = 0.0;
|
|
}
|
|
success = false;
|
|
displacementX = pointPlacementElement.elementsByTagName( "DisplacementX" ).item( 0 ).toElement().text().toDouble( &success );
|
|
if ( !success )
|
|
{
|
|
displacementX = 0.0;
|
|
}
|
|
displacementY = pointPlacementElement.elementsByTagName( "DisplacementY" ).item( 0 ).toElement().text().toDouble( &success );
|
|
if ( !success )
|
|
{
|
|
displacementY = 0.0;
|
|
}
|
|
}
|
|
QgsDebugMsg( "rotationAngle " + QString::number( rotationAngle ) );
|
|
|
|
myLabelAttributes->setOffset( displacementX, displacementY, QgsLabelAttributes::PointUnits );
|
|
myLabelAttributes->setAngle( rotationAngle );
|
|
}
|
|
} // end labelPlacement
|
|
vec->enableLabels( true );
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//from the specs: 'if a Label element is not provided ... then no text will be rendered'
|
|
return false;
|
|
} // end if a viable label element is provided
|
|
|
|
} // end if there is a viable text textSymbolizerElement
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
} // end if there are textSymbolizers
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
} // end if there are rule elements
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
} // end else from the beginning
|
|
}
|
|
|
|
// ------------------findUserLayerElement-------------------
|
|
|
|
QDomElement QgsSLDParser::findUserLayerElement( const QString& layerName ) const
|
|
{
|
|
QDomElement defaultResult;
|
|
if ( mXMLDoc )
|
|
{
|
|
QDomElement sldElement = mXMLDoc->documentElement();
|
|
if ( !sldElement.isNull() )
|
|
{
|
|
QDomNodeList UserLayerList = sldElement.elementsByTagName( "UserLayer" );
|
|
for ( int i = 0; i < UserLayerList.size(); ++i )
|
|
{
|
|
QDomNodeList nameList = UserLayerList.item( i ).toElement().elementsByTagName( "Name" );
|
|
if ( nameList.size() > 0 )
|
|
{
|
|
if ( nameList.item( 0 ).toElement().text() == layerName )
|
|
{
|
|
return UserLayerList.item( i ).toElement();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return defaultResult;
|
|
}
|
|
|
|
QList<QDomElement> QgsSLDParser::findNamedLayerElements( const QString& layerName ) const
|
|
{
|
|
QList<QDomElement> resultList;
|
|
if ( mXMLDoc )
|
|
{
|
|
QDomElement sldElement = mXMLDoc->documentElement();
|
|
if ( !sldElement.isNull() )
|
|
{
|
|
QDomNodeList NamedLayerList = sldElement.elementsByTagName( "NamedLayer" );
|
|
for ( int i = 0; i < NamedLayerList.size(); ++i )
|
|
{
|
|
QDomNodeList nameList = NamedLayerList.item( i ).toElement().elementsByTagName( "Name" );
|
|
if ( nameList.size() > 0 )
|
|
{
|
|
if ( nameList.item( 0 ).toElement().text() == layerName )
|
|
{
|
|
resultList.push_back( NamedLayerList.item( i ).toElement() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return resultList;
|
|
}
|
|
|
|
QDomElement QgsSLDParser::findUserStyleElement( const QDomElement& userLayerElement, const QString& styleName ) const
|
|
{
|
|
QDomElement defaultResult;
|
|
if ( !userLayerElement.isNull() )
|
|
{
|
|
QDomNodeList userStyleList = userLayerElement.elementsByTagName( "UserStyle" );
|
|
for ( int i = 0; i < userStyleList.size(); ++i )
|
|
{
|
|
QDomNodeList nameList = userStyleList.item( i ).toElement().elementsByTagName( "Name" );
|
|
if ( nameList.size() > 0 )
|
|
{
|
|
if ( nameList.item( 0 ).toElement().text() == styleName )
|
|
{
|
|
return userStyleList.item( i ).toElement();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return defaultResult;
|
|
}
|
|
|
|
int QgsSLDParser::layersAndStyles( QStringList& layers, QStringList& styles ) const
|
|
{
|
|
QgsDebugMsg( "Entering." );
|
|
layers.clear();
|
|
styles.clear();
|
|
|
|
if ( mXMLDoc )
|
|
{
|
|
QDomElement sldElem = mXMLDoc->documentElement();
|
|
if ( !sldElem.isNull() )
|
|
{
|
|
//go through all the children and search for <NamedLayers> and <UserLayers>
|
|
QDomNodeList layerNodes = sldElem.childNodes();
|
|
for ( int i = 0; i < layerNodes.size(); ++i )
|
|
{
|
|
QDomElement currentLayerElement = layerNodes.item( i ).toElement();
|
|
if ( currentLayerElement.localName() == "NamedLayer" )
|
|
{
|
|
QgsDebugMsg( "Found a NamedLayer" );
|
|
//layer name
|
|
QDomNodeList nameList = currentLayerElement.elementsByTagName/*NS*/( /*mSLDNamespace,*/ "Name" );
|
|
if ( nameList.length() < 1 )
|
|
{
|
|
continue; //a layer name is mandatory
|
|
}
|
|
QString layerName = nameList.item( 0 ).toElement().text();
|
|
|
|
//find the Named Styles and the corresponding names
|
|
QDomNodeList namedStyleList = currentLayerElement.elementsByTagName/*NS*/( /*mSLDNamespace,*/ "NamedStyle" );
|
|
for ( int j = 0; j < namedStyleList.size(); ++j )
|
|
{
|
|
QDomNodeList styleNameList = namedStyleList.item( j ).toElement().elementsByTagName/*NS*/( /*mSLDNamespace,*/ "Name" );
|
|
if ( styleNameList.size() < 1 )
|
|
{
|
|
continue; //a layer name is mandatory
|
|
}
|
|
QString styleName = styleNameList.item( 0 ).toElement().text();
|
|
QgsDebugMsg( "styleName is: " + styleName );
|
|
layers.push_back( layerName );
|
|
styles.push_back( styleName );
|
|
}
|
|
|
|
//named layers can also have User Styles
|
|
QDomNodeList userStyleList = currentLayerElement.elementsByTagName/*NS*/( /*mSLDNamespace,*/ "UserStyle" );
|
|
for ( int j = 0; j < userStyleList.size(); ++j )
|
|
{
|
|
QDomNodeList styleNameList = userStyleList.item( j ).toElement().elementsByTagName/*NS*/( /*mSLDNamespace,*/ "Name" );
|
|
if ( styleNameList.size() < 1 )
|
|
{
|
|
continue; //a layer name is mandatory
|
|
}
|
|
QString styleName = styleNameList.item( 0 ).toElement().text();
|
|
QgsDebugMsg( "styleName is: " + styleName );
|
|
layers.push_back( layerName );
|
|
styles.push_back( styleName );
|
|
}
|
|
}
|
|
else if ( currentLayerElement.localName() == "UserLayer" )
|
|
{
|
|
QgsDebugMsg( "Found a UserLayer" );
|
|
//layer name
|
|
QDomNodeList nameList = currentLayerElement.elementsByTagName/*NS*/( /*mSLDNamespace,*/ "Name" );
|
|
if ( nameList.length() < 1 )
|
|
{
|
|
QgsDebugMsg( "Namelist size is <1" );
|
|
continue; //a layer name is mandatory
|
|
}
|
|
QString layerName = nameList.item( 0 ).toElement().text();
|
|
QgsDebugMsg( "layerName is: " + layerName );
|
|
//find the User Styles and the corresponding names
|
|
QDomNodeList userStyleList = currentLayerElement.elementsByTagName/*NS*/( /*mSLDNamespace,*/ "UserStyle" );
|
|
for ( int j = 0; j < userStyleList.size(); ++j )
|
|
{
|
|
QDomNodeList styleNameList = userStyleList.item( j ).toElement().elementsByTagName/*NS*/( /*mSLDNamespace,*/ "Name" );
|
|
if ( styleNameList.size() < 1 )
|
|
{
|
|
QgsDebugMsg( "Namelist size is <1" );
|
|
continue;
|
|
}
|
|
|
|
QString styleName = styleNameList.item( 0 ).toElement().text();
|
|
QgsDebugMsg( "styleName is: " + styleName );
|
|
layers.push_back( layerName );
|
|
styles.push_back( styleName );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
QgsMapLayer* QgsSLDParser::mapLayerFromUserLayer( const QDomElement& userLayerElem, const QString& layerName, bool allowCaching ) const
|
|
{
|
|
QgsDebugMsg( "Entering." );
|
|
QgsMSLayerBuilder* layerBuilder = 0;
|
|
QDomElement builderRootElement;
|
|
|
|
//hosted vector data?
|
|
QDomNode hostedVDSNode = userLayerElem.namedItem( "HostedVDS" );
|
|
if ( !hostedVDSNode.isNull() )
|
|
{
|
|
builderRootElement = hostedVDSNode.toElement();
|
|
layerBuilder = new QgsHostedVDSBuilder();
|
|
}
|
|
|
|
//hosted raster data?
|
|
QDomNode hostedRDSNode = userLayerElem.namedItem( "HostedRDS" );
|
|
if ( !hostedRDSNode.isNull() )
|
|
{
|
|
builderRootElement = hostedRDSNode.toElement();
|
|
layerBuilder = new QgsHostedRDSBuilder();
|
|
}
|
|
|
|
//remote OWS (WMS, WFS, WCS)?
|
|
QDomNode remoteOWSNode = userLayerElem.namedItem( "RemoteOWS" );
|
|
if ( !remoteOWSNode.isNull() )
|
|
{
|
|
builderRootElement = remoteOWSNode.toElement();
|
|
layerBuilder = new QgsRemoteOWSBuilder( mParameterMap );
|
|
}
|
|
|
|
//remote vector/raster datasource
|
|
QDomNode remoteRDSNode = userLayerElem.namedItem( "RemoteRDS" );
|
|
if ( !remoteRDSNode.isNull() )
|
|
{
|
|
builderRootElement = remoteRDSNode.toElement();
|
|
layerBuilder = new QgsRemoteDataSourceBuilder();
|
|
QgsDebugMsg( "Detected remote raster datasource" );
|
|
}
|
|
QDomNode remoteVDSNode = userLayerElem.namedItem( "RemoteVDS" );
|
|
|
|
if ( !remoteVDSNode.isNull() )
|
|
{
|
|
builderRootElement = remoteVDSNode.toElement();
|
|
layerBuilder = new QgsRemoteDataSourceBuilder();
|
|
QgsDebugMsg( "Detected remote vector datasource" );
|
|
}
|
|
|
|
//sent vector/raster datasource
|
|
QDomNode sentVDSNode = userLayerElem.namedItem( "SentVDS" );
|
|
if ( !sentVDSNode.isNull() )
|
|
{
|
|
builderRootElement = sentVDSNode.toElement();
|
|
layerBuilder = new QgsSentDataSourceBuilder();
|
|
}
|
|
|
|
QDomNode sentRDSNode = userLayerElem.namedItem( "SentRDS" );
|
|
if ( !sentRDSNode.isNull() )
|
|
{
|
|
builderRootElement = sentRDSNode.toElement();
|
|
layerBuilder = new QgsSentDataSourceBuilder();
|
|
}
|
|
|
|
if ( !layerBuilder )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
QgsMapLayer* theMapLayer = layerBuilder->createMapLayer( builderRootElement, layerName, mFilesToRemove, mLayersToRemove, allowCaching );
|
|
if ( theMapLayer )
|
|
{
|
|
setCrsForLayer( builderRootElement, theMapLayer ); //consider attributes "epsg" and "proj"
|
|
}
|
|
|
|
//maybe the datasource is defined in the fallback SLD?
|
|
if ( !theMapLayer && mFallbackParser )
|
|
{
|
|
QList<QgsMapLayer*> fallbackList = mFallbackParser->mapLayerFromStyle( layerName, "", allowCaching );
|
|
if ( fallbackList.size() > 0 )
|
|
{
|
|
QgsMapLayer* fallbackLayer = fallbackList.at( 0 ); //todo: prevent crash if layer list is empty
|
|
if ( fallbackLayer )
|
|
{
|
|
theMapLayer = dynamic_cast<QgsVectorLayer*>( fallbackLayer );
|
|
}
|
|
}
|
|
}
|
|
|
|
//GML from outside the SLD?
|
|
if ( !theMapLayer )
|
|
{
|
|
QMap<QString, QDomDocument*>::const_iterator gmlIt = mExternalGMLDatasets.find( layerName );
|
|
|
|
if ( gmlIt != mExternalGMLDatasets.end() )
|
|
{
|
|
QgsDebugMsg( "Trying to get maplayer from external GML" );
|
|
theMapLayer = vectorLayerFromGML( gmlIt.value()->documentElement() );
|
|
}
|
|
}
|
|
|
|
//raster layer from interpolation
|
|
|
|
QDomNode rasterInterpolationNode = userLayerElem.namedItem( "RasterInterpolation" );
|
|
if ( !rasterInterpolationNode.isNull() )
|
|
{
|
|
QgsVectorLayer* vectorCast = dynamic_cast<QgsVectorLayer*>( theMapLayer );
|
|
if ( vectorCast )
|
|
{
|
|
builderRootElement = rasterInterpolationNode.toElement();
|
|
layerBuilder = new QgsInterpolationLayerBuilder( vectorCast );
|
|
theMapLayer = layerBuilder->createMapLayer( builderRootElement, layerName, mFilesToRemove, mLayersToRemove, allowCaching );
|
|
}
|
|
}
|
|
|
|
return theMapLayer;
|
|
}
|
|
|
|
QgsVectorLayer* QgsSLDParser::vectorLayerFromGML( const QDomElement gmlRootElement ) const
|
|
{
|
|
QgsDebugMsg( "Entering." );
|
|
|
|
//QString tempFilePath = QgsMSUtils::createTempFilePath();
|
|
//QFile tempFile(tempFilePath);
|
|
QTemporaryFile* tmpFile = new QTemporaryFile();
|
|
if ( tmpFile->open() )
|
|
{
|
|
mFilesToRemove.push_back( tmpFile );
|
|
QTextStream tempFileStream( tmpFile );
|
|
gmlRootElement.save( tempFileStream, 4 );
|
|
tmpFile->close();
|
|
}
|
|
else
|
|
{
|
|
delete tmpFile;
|
|
return 0;
|
|
}
|
|
|
|
QgsVectorLayer* theVectorLayer = new QgsVectorLayer( tmpFile->fileName(), layerNameFromUri( tmpFile->fileName() ), "WFS" );
|
|
if ( !theVectorLayer || !theVectorLayer->isValid() )
|
|
{
|
|
QgsDebugMsg( "invalid maplayer" );
|
|
return 0;
|
|
}
|
|
QgsDebugMsg( "returning maplayer" );
|
|
|
|
mLayersToRemove.push_back( theVectorLayer ); //make sure the layer gets deleted after each request
|
|
|
|
return theVectorLayer;
|
|
}
|
|
|
|
QgsVectorLayer* QgsSLDParser::contourLayerFromRaster( const QDomElement& userStyleElem, QgsRasterLayer* rasterLayer ) const
|
|
{
|
|
QgsDebugMsg( "Entering." );
|
|
|
|
if ( !rasterLayer )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//get <ContourSymbolizer> element
|
|
QDomNodeList contourNodeList = userStyleElem.elementsByTagName( "ContourSymbolizer" );
|
|
if ( contourNodeList.size() < 1 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
QDomElement contourSymbolizerElem = contourNodeList.item( 0 ).toElement();
|
|
if ( contourSymbolizerElem.isNull() )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
double equidistance, minValue, maxValue, offset;
|
|
QString propertyName;
|
|
|
|
equidistance = contourSymbolizerElem.attribute( "equidistance" ).toDouble();
|
|
minValue = contourSymbolizerElem.attribute( "minValue" ).toDouble();
|
|
maxValue = contourSymbolizerElem.attribute( "maxValue" ).toDouble();
|
|
offset = contourSymbolizerElem.attribute( "offset" ).toDouble();
|
|
propertyName = contourSymbolizerElem.attribute( "propertyName" );
|
|
|
|
if ( equidistance <= 0.0 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
QTemporaryFile* tmpFile1 = new QTemporaryFile();
|
|
tmpFile1->open();
|
|
mFilesToRemove.push_back( tmpFile1 );
|
|
QString tmpBaseName = tmpFile1->fileName();
|
|
QString tmpFileName = tmpBaseName + ".shp";
|
|
|
|
//hack: use gdal_contour first to write into a temporary file
|
|
/* todo: use GDALContourGenerate( hBand, dfInterval, dfOffset,
|
|
nFixedLevelCount, adfFixedLevels,
|
|
bNoDataSet, dfNoData,
|
|
hLayer, 0, nElevField,
|
|
GDALTermProgress, NULL );*/
|
|
|
|
|
|
//do the stuff that is also done in the main method of gdal_contour...
|
|
/* -------------------------------------------------------------------- */
|
|
/* Open source raster file. */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALRasterBandH hBand;
|
|
GDALDatasetH hSrcDS;
|
|
|
|
int numberOfLevels = 0;
|
|
double currentLevel = 0.0;
|
|
|
|
if ( maxValue > minValue )
|
|
{
|
|
//find first level
|
|
currentLevel = ( int )(( minValue - offset ) / equidistance + 0.5 ) * equidistance + offset;
|
|
while ( currentLevel <= maxValue )
|
|
{
|
|
++numberOfLevels;
|
|
currentLevel += equidistance;
|
|
}
|
|
}
|
|
|
|
double *adfFixedLevels = new double[numberOfLevels];
|
|
int nFixedLevelCount = numberOfLevels;
|
|
currentLevel = ( int )(( minValue - offset ) / equidistance + 0.5 ) * equidistance + offset;
|
|
for ( int i = 0; i < numberOfLevels; ++i )
|
|
{
|
|
adfFixedLevels[i] = currentLevel;
|
|
currentLevel += equidistance;
|
|
}
|
|
int nBandIn = 1;
|
|
double dfInterval = equidistance, dfNoData = 0.0, dfOffset = offset;
|
|
|
|
int b3D = FALSE, bNoDataSet = FALSE, bIgnoreNoData = FALSE;
|
|
|
|
hSrcDS = GDALOpen( TO8( rasterLayer->source() ), GA_ReadOnly );
|
|
if ( hSrcDS == NULL )
|
|
exit( 2 );
|
|
|
|
hBand = GDALGetRasterBand( hSrcDS, nBandIn );
|
|
if ( hBand == NULL )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Band %d does not exist on dataset.",
|
|
nBandIn );
|
|
}
|
|
|
|
if ( !bNoDataSet && !bIgnoreNoData )
|
|
dfNoData = GDALGetRasterNoDataValue( hBand, &bNoDataSet );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Try to get a coordinate system from the raster. */
|
|
/* -------------------------------------------------------------------- */
|
|
OGRSpatialReferenceH hSRS = NULL;
|
|
|
|
const char *pszWKT = GDALGetProjectionRef( hBand );
|
|
|
|
if ( pszWKT != NULL && strlen( pszWKT ) != 0 )
|
|
hSRS = OSRNewSpatialReference( pszWKT );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create the outputfile. */
|
|
/* -------------------------------------------------------------------- */
|
|
OGRDataSourceH hDS;
|
|
OGRSFDriverH hDriver = OGRGetDriverByName( "ESRI Shapefile" );
|
|
OGRFieldDefnH hFld;
|
|
OGRLayerH hLayer;
|
|
int nElevField = -1;
|
|
|
|
if ( hDriver == NULL )
|
|
{
|
|
fprintf( FCGI_stderr, "Unable to find format driver named 'ESRI Shapefile'.\n" );
|
|
exit( 10 );
|
|
}
|
|
|
|
hDS = OGR_Dr_CreateDataSource( hDriver, TO8( tmpFileName ), NULL );
|
|
if ( hDS == NULL )
|
|
exit( 1 );
|
|
|
|
hLayer = OGR_DS_CreateLayer( hDS, "contour", hSRS,
|
|
b3D ? wkbLineString25D : wkbLineString,
|
|
NULL );
|
|
if ( hLayer == NULL )
|
|
exit( 1 );
|
|
|
|
hFld = OGR_Fld_Create( "ID", OFTInteger );
|
|
OGR_Fld_SetWidth( hFld, 8 );
|
|
OGR_L_CreateField( hLayer, hFld, FALSE );
|
|
OGR_Fld_Destroy( hFld );
|
|
|
|
if ( !propertyName.isEmpty() )
|
|
{
|
|
hFld = OGR_Fld_Create( TO8( propertyName ), OFTReal );
|
|
OGR_Fld_SetWidth( hFld, 12 );
|
|
OGR_Fld_SetPrecision( hFld, 3 );
|
|
OGR_L_CreateField( hLayer, hFld, FALSE );
|
|
OGR_Fld_Destroy( hFld );
|
|
nElevField = 1;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Invoke. */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALContourGenerate( hBand, dfInterval, dfOffset,
|
|
nFixedLevelCount, adfFixedLevels,
|
|
bNoDataSet, dfNoData,
|
|
hLayer, 0, nElevField,
|
|
GDALTermProgress, NULL );
|
|
|
|
delete adfFixedLevels;
|
|
|
|
OGR_DS_Destroy( hDS );
|
|
GDALClose( hSrcDS );
|
|
|
|
//todo: store those three files elsewhere...
|
|
//mark shp, dbf and shx to delete after the request
|
|
mFilePathsToRemove.push_back( tmpBaseName + ".shp" );
|
|
mFilePathsToRemove.push_back( tmpBaseName + ".dbf" );
|
|
mFilePathsToRemove.push_back( tmpBaseName + ".shx" );
|
|
|
|
QgsVectorLayer* contourLayer = new QgsVectorLayer( tmpFileName, "layer", "ogr" );
|
|
|
|
//create renderer
|
|
QgsFeatureRendererV2* theRenderer = rendererFromUserStyle( userStyleElem, contourLayer );
|
|
contourLayer->setRendererV2( theRenderer );
|
|
|
|
//add labelling if requested
|
|
labelSettingsFromUserStyle( userStyleElem, contourLayer );
|
|
|
|
QgsDebugMsg( "Returning the contour layer" );
|
|
return contourLayer;
|
|
}
|
|
|
|
QDomDocument QgsSLDParser::getStyle( const QString& styleName, const QString& layerName ) const
|
|
{
|
|
QDomElement userLayerElement = findUserLayerElement( layerName );
|
|
|
|
if ( userLayerElement.isNull() )
|
|
{
|
|
throw QgsMapServiceException( "LayerNotDefined", "Operation request is for a Layer not offered by the server." );
|
|
}
|
|
|
|
QDomElement userStyleElement = findUserStyleElement( userLayerElement, styleName );
|
|
|
|
if ( userStyleElement.isNull() )
|
|
{
|
|
throw QgsMapServiceException( "StyleNotDefined", "Operation request references a Style not offered by the server." );
|
|
}
|
|
|
|
QDomDocument styleDoc;
|
|
styleDoc.appendChild( styleDoc.importNode( userStyleElement, true ) );
|
|
return styleDoc;
|
|
}
|
|
|
|
QString QgsSLDParser::layerNameFromUri( const QString& uri ) const
|
|
{
|
|
//file based?
|
|
QFileInfo f( uri );
|
|
if ( f.exists() )
|
|
{
|
|
return f.baseName();
|
|
}
|
|
|
|
//http based?
|
|
if ( uri.startsWith( "http", Qt::CaseInsensitive ) )
|
|
{
|
|
return uri;
|
|
}
|
|
|
|
//database?
|
|
if ( uri.contains( "dbname" ) )
|
|
{
|
|
//take tablename
|
|
QStringList spaceSplit = uri.split( " " );
|
|
QStringList::const_iterator slIt;
|
|
for ( slIt = spaceSplit.constBegin(); slIt != spaceSplit.constEnd(); ++slIt )
|
|
{
|
|
if ( slIt->startsWith( "table" ) )
|
|
{
|
|
return slIt->section( "=", 1, 1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
void QgsSLDParser::setOpacityForLayer( const QDomElement& layerElem, QgsMapLayer* layer ) const
|
|
{
|
|
QDomNode opacityNode = layerElem.namedItem( "Opacity" );
|
|
if ( !layer || opacityNode.isNull() )
|
|
{
|
|
return ;
|
|
}
|
|
QDomElement opacityElem = opacityNode.toElement();
|
|
bool conversionSuccess;
|
|
int opacityValue = opacityElem.text().toInt( &conversionSuccess );
|
|
if ( !conversionSuccess )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//make sure value is between 0 and 255
|
|
if ( opacityValue > 255 )
|
|
{
|
|
opacityValue = 255;
|
|
}
|
|
else if ( opacityValue < 0 )
|
|
{
|
|
opacityValue = 0;
|
|
}
|
|
|
|
QgsDebugMsg( "Setting opacity value: " + QString::number( opacityValue ) );
|
|
layer->setTransparency( opacityValue );
|
|
}
|
|
|
|
void QgsSLDParser::clearRasterSymbology( QgsRasterLayer* rl ) const
|
|
{
|
|
if ( rl )
|
|
{
|
|
if ( rl->rasterType() == QgsRasterLayer::GrayOrUndefined )
|
|
{
|
|
rl->setDrawingStyle( QgsRasterLayer::SingleBandPseudoColor );
|
|
}
|
|
}
|
|
}
|
|
|
|
void QgsSLDParser::setCrsForLayer( const QDomElement& layerElem, QgsMapLayer* ml ) const
|
|
{
|
|
//create CRS if specified as attribute ("epsg" or "proj")
|
|
QString epsg = layerElem.attribute( "epsg", "" );
|
|
if ( !epsg.isEmpty() )
|
|
{
|
|
bool conversionOk;
|
|
int epsgnr = epsg.toInt( &conversionOk );
|
|
if ( conversionOk )
|
|
{
|
|
//set spatial ref sys
|
|
QgsCoordinateReferenceSystem srs;
|
|
srs.createFromOgcWmsCrs( QString( "EPSG:%1" ).arg( epsgnr ) );
|
|
ml->setCrs( srs );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
QString projString = layerElem.attribute( "proj", "" );
|
|
if ( !projString.isEmpty() )
|
|
{
|
|
QgsCoordinateReferenceSystem srs;
|
|
srs.createFromProj4( projString );
|
|
ml->setCrs( srs );
|
|
}
|
|
}
|
|
}
|
|
|
|
QgsComposition* QgsSLDParser::initComposition( const QString& composerTemplate, QgsMapRenderer* mapRenderer, QList< QgsComposerMap*>& mapList, QList< QgsComposerLabel* >& labelList ) const
|
|
{
|
|
if ( mFallbackParser )
|
|
{
|
|
return mFallbackParser->initComposition( composerTemplate, mapRenderer, mapList, labelList );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void QgsSLDParser::printCapabilities( QDomElement& parentElement, QDomDocument& doc ) const
|
|
{
|
|
if ( mFallbackParser )
|
|
{
|
|
mFallbackParser->printCapabilities( parentElement, doc );
|
|
}
|
|
}
|
|
|
|
bool QgsSLDParser::featureInfoWithWktGeometry() const
|
|
{
|
|
if ( mFallbackParser )
|
|
{
|
|
return mFallbackParser->featureInfoWithWktGeometry();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
QHash<QString, QString> QgsSLDParser::featureInfoLayerAliasMap() const
|
|
{
|
|
if ( mFallbackParser )
|
|
{
|
|
return mFallbackParser->featureInfoLayerAliasMap();
|
|
}
|
|
return QHash<QString, QString>();
|
|
}
|
|
|
|
bool QgsSLDParser::featureInfoFormatSIA2045() const
|
|
{
|
|
if ( mFallbackParser )
|
|
{
|
|
return mFallbackParser->featureInfoFormatSIA2045();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void QgsSLDParser::drawOverlays( QPainter* p, int dpi, int width, int height ) const
|
|
{
|
|
if ( mFallbackParser )
|
|
{
|
|
mFallbackParser->drawOverlays( p, dpi, width, height );
|
|
}
|
|
}
|
|
|
|
#ifdef DIAGRAMSERVER
|
|
int QgsSLDParser::overlaysFromUserStyle( const QDomElement& userStyleElement, QgsVectorLayer* vec ) const
|
|
{
|
|
if ( userStyleElement.isNull() || !vec )
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
QgsVectorOverlay* currentOverlay = 0;
|
|
|
|
//look for <DiagramSymbolizer>
|
|
QDomNodeList diagramSymbolizerList = userStyleElement.elementsByTagName/*NS*/( /*mSLDNamespace,*/ "DiagramSymbolizer" );
|
|
for ( int i = 0; i < diagramSymbolizerList.size(); ++i )
|
|
{
|
|
currentOverlay = vectorOverlayFromDiagramSymbolizer( diagramSymbolizerList.at( i ).toElement(), vec );
|
|
if ( currentOverlay )
|
|
{
|
|
currentOverlay->setDisplayFlag( true );
|
|
vec->addOverlay( currentOverlay );
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
QgsVectorOverlay* QgsSLDParser::vectorOverlayFromDiagramSymbolizer( const QDomElement& symbolizerElem, QgsVectorLayer* vec ) const
|
|
{
|
|
if ( symbolizerElem.isNull() )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
QDomNodeList diagramNodeList = symbolizerElem.elementsByTagName( "Diagram" );
|
|
if ( diagramNodeList.size() < 1 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
QDomElement diagramElem = diagramNodeList.at( 0 ).toElement();
|
|
if ( diagramElem.isNull() )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
QgsVectorDataProvider* provider = vec->dataProvider();
|
|
if ( !provider )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
QgsDiagramOverlay* theOverlay = 0;
|
|
QgsDiagramFactory* theFactory = 0;
|
|
QList<QgsDiagramItem> theItems;
|
|
QList<int> scalingAttributes;
|
|
QgsAttributeList factoryCategoryAttributes;
|
|
QgsDiagramRenderer::ItemInterpretation interpretation = QgsDiagramRenderer::DISCRETE; //discrete or linear
|
|
|
|
//scale
|
|
double scaleFactor = scaleFactorFromScaleTag( diagramElem.namedItem( "Scale" ).toElement() );
|
|
|
|
//size
|
|
QDomNodeList sizeNodeList = diagramElem.elementsByTagName( "Size" );
|
|
if ( sizeNodeList.size() > 0 )
|
|
{
|
|
QDomElement sizeElem = sizeNodeList.at( 0 ).toElement();
|
|
//fixed value or categorize/interpolate?
|
|
QDomNode valueNode = sizeElem.namedItem( "Value" );
|
|
QDomNode propertyNameNode = sizeElem.namedItem( "PropertyName" );
|
|
|
|
if ( !valueNode.isNull() ) //fixed value
|
|
{
|
|
double value = valueNode.toElement().text().toDouble();
|
|
QgsDiagramItem item;
|
|
item.value = 0;
|
|
item.size = ( int )value;
|
|
theItems.push_back( item );
|
|
interpretation = QgsDiagramRenderer::CONSTANT;
|
|
}
|
|
else if ( !propertyNameNode.isNull() )//take size from attribute(s)
|
|
{
|
|
QList<QDomElement> propertyNameElements;
|
|
int currentScalingIndex;
|
|
QDomElement currentElement = propertyNameNode.toElement();
|
|
while ( !currentElement.isNull() )
|
|
{
|
|
currentScalingIndex = provider->fieldNameIndex( currentElement.text() );
|
|
if ( currentScalingIndex != -1 )
|
|
{
|
|
scalingAttributes.push_back( currentScalingIndex );
|
|
}
|
|
currentElement = currentElement.nextSiblingElement( "PropertyName" );
|
|
}
|
|
//add all the attributes as scaling attributes
|
|
interpretation = QgsDiagramRenderer::ATTRIBUTE;
|
|
|
|
}
|
|
else //categorize or interpolate
|
|
{
|
|
QDomNodeList categorizeNodeList = sizeElem.elementsByTagName( "Categorize" );
|
|
QDomNodeList interpolateNodeList = sizeElem.elementsByTagName( "Interpolate" );
|
|
if ( categorizeNodeList.size() > 0 )
|
|
{
|
|
QDomElement categorizeElem = categorizeNodeList.at( 0 ).toElement();
|
|
QString scalingAttributeName;
|
|
if ( diagramItemsFromCategorize( categorizeElem, theItems, scalingAttributeName ) != 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
scalingAttributes.push_back( provider->fieldNameIndex( scalingAttributeName ) );
|
|
interpretation = QgsDiagramRenderer::DISCRETE;
|
|
}
|
|
else if ( interpolateNodeList.size() > 0 )
|
|
{
|
|
QDomElement interpolateElem = interpolateNodeList.at( 0 ).toElement();
|
|
QString scalingAttributeName;
|
|
if ( diagramItemsFromInterpolate( interpolateElem, theItems, scalingAttributeName ) != 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
scalingAttributes.push_back( provider->fieldNameIndex( scalingAttributeName ) );
|
|
if ( interpolateElem.attribute( "mode" ) == "linear" )
|
|
{
|
|
interpretation = QgsDiagramRenderer::LINEAR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
QgsDiagramRenderer* theRenderer = new QgsDiagramRenderer( scalingAttributes );
|
|
theRenderer->setDiagramItems( theItems );
|
|
theRenderer->setItemInterpretation( interpretation );
|
|
theRenderer->setScaleFactor( scaleFactor );
|
|
|
|
|
|
//opacity
|
|
|
|
//rotation
|
|
|
|
//displacement
|
|
|
|
QDomNodeList wknNodeList = diagramElem.elementsByTagName( "WellKnownName" );
|
|
QDomNodeList svgSymbolNodeList = diagramElem.elementsByTagName( "SvgSymbol" );
|
|
|
|
if ( wknNodeList.size() > 0 ) //well known name diagram
|
|
{
|
|
//well known diagram name
|
|
QString wellKnownName = wknNodeList.at( 0 ).toElement().text();
|
|
if ( wellKnownName == "Pie" )
|
|
{
|
|
theFactory = new QgsPieDiagramFactory();
|
|
}
|
|
else if ( wellKnownName == "Bar" )
|
|
{
|
|
theFactory = new QgsBarDiagramFactory();
|
|
}
|
|
else
|
|
{
|
|
//unknown diagram type
|
|
|
|
}
|
|
|
|
|
|
//subtype
|
|
|
|
//categories, take field and fill color for now and add it to QgsWKNDiagramFactory
|
|
QList<QgsDiagramCategory> diagramCategories;
|
|
|
|
if ( symbologyFromCategoryTags( diagramElem, provider, diagramCategories ) != 0 )
|
|
{
|
|
delete theRenderer;
|
|
delete theFactory;
|
|
return 0;
|
|
}
|
|
|
|
QList<QgsDiagramCategory>::const_iterator c_it = diagramCategories.constBegin();
|
|
for ( ; c_it != diagramCategories.constEnd(); ++c_it )
|
|
{
|
|
(( QgsWKNDiagramFactory* )theFactory )->addCategory( *c_it );
|
|
//diagram renderer also needs to know which attributes are needed
|
|
factoryCategoryAttributes.push_back( c_it->propertyIndex() );
|
|
}
|
|
|
|
//3D?
|
|
|
|
(( QgsWKNDiagramFactory* )theFactory )->setScalingAttributes( scalingAttributes );
|
|
(( QgsWKNDiagramFactory* )theFactory )->setDiagramType( wellKnownName );
|
|
|
|
}
|
|
else if ( svgSymbolNodeList.size() > 0 ) //svg symbol?
|
|
{
|
|
theFactory = new QgsSVGDiagramFactory();
|
|
QDomDocument svgDocument;
|
|
svgDocument.appendChild( svgDocument.importNode( svgSymbolNodeList.at( 0 ).toElement(), true ) );
|
|
|
|
if ( !(( QgsSVGDiagramFactory* )theFactory )->setSVGData( svgDocument.toByteArray() ) )
|
|
{
|
|
delete theRenderer; delete theFactory;
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delete theRenderer;
|
|
return 0;
|
|
}
|
|
|
|
theOverlay = new QgsDiagramOverlay( vec );
|
|
|
|
if ( theOverlay && theRenderer && theFactory )
|
|
{
|
|
theRenderer->setFactory( theFactory );
|
|
//overlay needs to fetch scaling attributes and category attributes
|
|
theOverlay->setAttributes( factoryCategoryAttributes + scalingAttributes );
|
|
theOverlay->setDiagramRenderer( theRenderer );
|
|
return theOverlay;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QgsSLDParser::diagramItemsFromCategorize( const QDomElement& categorizeElement, QList<QgsDiagramItem>& items, QString& attribute ) const
|
|
{
|
|
items.clear();
|
|
|
|
//get name of scaling attribute
|
|
QDomNode lookupNode = categorizeElement.namedItem( "LookupValue" );
|
|
if ( lookupNode.isNull() )
|
|
{
|
|
return 1;
|
|
}
|
|
QDomNode propertyNameNode = lookupNode.namedItem( "PropertyName" );
|
|
if ( propertyNameNode.isNull() )
|
|
{
|
|
return 2;
|
|
}
|
|
attribute = propertyNameNode.toElement().text();
|
|
|
|
QDomNodeList valueNodeList = categorizeElement.elementsByTagName( "Value" );
|
|
QDomNodeList thresholdNodeList = categorizeElement.elementsByTagName( "Threshold" );
|
|
|
|
if ( ! valueNodeList.size() == ( thresholdNodeList.size() + 1 ) )
|
|
{
|
|
QgsDebugMsg( "error, sizes of value and threshold lists do not match" );
|
|
return 3;
|
|
}
|
|
|
|
if ( valueNodeList.size() < 1 || thresholdNodeList.size() < 1 )
|
|
{
|
|
return 4;
|
|
}
|
|
|
|
QVariant currentThreshold;
|
|
QgsDiagramItem currentItem;
|
|
|
|
//In SE specification, there is a single value tag that stands for values below the first threshold
|
|
//In QGIS, this is modelled with an extra item
|
|
currentItem.size = valueNodeList.at( 0 ).toElement().text().toInt();
|
|
currentItem.value = thresholdNodeList.at( 0 ).toElement().text();
|
|
items.push_back( currentItem );
|
|
|
|
int vIndex = 1;
|
|
int tIndex = 0;
|
|
|
|
for ( ; vIndex < valueNodeList.size() && tIndex < thresholdNodeList.size(); ++vIndex, ++tIndex )
|
|
{
|
|
currentItem.size = ( int )( valueNodeList.at( vIndex ).toElement().text().toDouble() );
|
|
currentItem.value = thresholdNodeList.at( tIndex ).toElement().text();
|
|
items.push_back( currentItem );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QgsSLDParser::diagramItemsFromInterpolate( const QDomElement& interpolateElement, QList<QgsDiagramItem>& items, QString& attribute ) const
|
|
{
|
|
items.clear();
|
|
|
|
//get name of scaling attribute
|
|
QDomNode lookupNode = interpolateElement.namedItem( "LookupValue" );
|
|
if ( lookupNode.isNull() )
|
|
{
|
|
return 1;
|
|
}
|
|
QDomNode propertyNameNode = lookupNode.namedItem( "PropertyName" );
|
|
if ( propertyNameNode.isNull() )
|
|
{
|
|
return 2;
|
|
}
|
|
attribute = propertyNameNode.toElement().text();
|
|
|
|
//<InterpolationPoint>
|
|
QgsDiagramItem currentItem;
|
|
QDomNode dataNode, valueNode;
|
|
|
|
QDomNodeList interpolationPointList = interpolateElement.elementsByTagName( "InterpolationPoint" );
|
|
for ( int i = 0; i < interpolationPointList.size(); ++i )
|
|
{
|
|
//<Data>
|
|
//<Value> (size)
|
|
dataNode = interpolationPointList.at( i ).namedItem( "Data" );
|
|
valueNode = interpolationPointList.at( i ).namedItem( "Value" );
|
|
if ( dataNode.isNull() || valueNode.isNull() )
|
|
{
|
|
continue;
|
|
}
|
|
currentItem.size = ( int )( valueNode.toElement().text().toDouble() );
|
|
currentItem.value = dataNode.toElement().text().toDouble();
|
|
items.push_back( currentItem );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int QgsSLDParser::symbologyFromCategoryTags( const QDomElement& diagramElement, const QgsVectorDataProvider* p, QList<QgsDiagramCategory>& categories ) const
|
|
{
|
|
if ( !p )
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
QDomNodeList categoryList = diagramElement.elementsByTagName( "Category" );
|
|
|
|
categories.clear();
|
|
|
|
for ( int i = 0; i < categoryList.size(); ++i )
|
|
{
|
|
QgsDiagramCategory currentCategory;
|
|
QPen currentPen( Qt::NoPen );
|
|
QBrush currentBrush( Qt::SolidPattern );
|
|
|
|
//look for PropertyName and fill
|
|
QDomNodeList propertyNameList = categoryList.at( i ).toElement().elementsByTagName( "PropertyName" );
|
|
if ( propertyNameList.size() < 1 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//read svg parameters and create brushes and pens from it
|
|
QDomNodeList SvgParamList = categoryList.at( i ).toElement().elementsByTagName( "SvgParameter" );
|
|
for ( int j = 0; j < SvgParamList.size(); ++j )
|
|
{
|
|
QDomElement svgParamElem = SvgParamList.at( j ).toElement();
|
|
if ( svgParamElem.attribute( "name" ) == "fill" )
|
|
{
|
|
currentBrush.setColor( QColor( svgParamElem.text() ) );
|
|
currentBrush.setStyle( Qt::SolidPattern );
|
|
}
|
|
else if ( svgParamElem.attribute( "name" ) == "stroke" )
|
|
{
|
|
currentPen.setColor( QColor( svgParamElem.text() ) );
|
|
currentPen.setStyle( Qt::SolidLine );
|
|
}
|
|
else if ( svgParamElem.attribute( "name" ) == "stroke-width" )
|
|
{
|
|
currentPen.setWidth( svgParamElem.text().toInt() );
|
|
currentPen.setStyle( Qt::SolidLine );
|
|
}
|
|
}
|
|
|
|
//Gap?
|
|
QDomNodeList gapNodeList = categoryList.at( i ).toElement().elementsByTagName( "Gap" );
|
|
if ( gapNodeList.size() > 0 )
|
|
{
|
|
currentCategory.setGap( gapNodeList.at( 0 ).toElement().text().toInt() );
|
|
}
|
|
|
|
currentCategory.setPen( currentPen );
|
|
currentCategory.setBrush( currentBrush );
|
|
currentCategory.setPropertyIndex( p->fieldNameIndex( propertyNameList.at( 0 ).toElement().text() ) );
|
|
categories.push_back( currentCategory );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
double QgsSLDParser::scaleFactorFromScaleTag( const QDomElement& scaleElem ) const
|
|
{
|
|
if ( scaleElem.isNull() )
|
|
{
|
|
return 1.0;
|
|
}
|
|
|
|
double minScaleDenom, maxScaleDenom, minScaleSizeMult, maxScaleSizeMult;
|
|
|
|
QDomElement minScaleDenomElem = scaleElem.namedItem( "MinScaleDenominator" ).toElement();
|
|
QDomElement maxScaleDenomElem = scaleElem.namedItem( "MaxScaleDenominator" ).toElement();
|
|
QDomElement minScaleSizeMultElem = scaleElem.namedItem( "MinScaleSizeMultiplication" ).toElement();
|
|
QDomElement maxScaleSizeMultElem = scaleElem.namedItem( "MaxScaleSizeMultiplication" ).toElement();
|
|
|
|
if ( minScaleDenomElem.isNull() || maxScaleDenomElem.isNull() || minScaleSizeMultElem.isNull() || maxScaleSizeMultElem.isNull() )
|
|
{
|
|
return 1.0;
|
|
}
|
|
|
|
minScaleDenom = minScaleDenomElem.text().toDouble();
|
|
maxScaleDenom = maxScaleDenomElem.text().toDouble();
|
|
minScaleSizeMult = minScaleSizeMultElem.text().toDouble();
|
|
maxScaleSizeMult = maxScaleSizeMultElem.text().toDouble();
|
|
|
|
if ( mScaleDenominator <= minScaleDenom )
|
|
{
|
|
return minScaleSizeMult;
|
|
}
|
|
else if ( mScaleDenominator >= maxScaleDenom )
|
|
{
|
|
return maxScaleSizeMult;
|
|
}
|
|
else
|
|
{
|
|
double factor = ( mScaleDenominator - minScaleDenom ) / ( maxScaleDenom - minScaleDenom ) * ( maxScaleSizeMult - minScaleSizeMult ) + minScaleSizeMult;
|
|
return factor;
|
|
}
|
|
}
|
|
|
|
#endif //DIAGRAMSERVER
|