From a9c830e67b7fe0e7f66fc23b5a5a85b7b8ac5c61 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Tue, 30 Jun 2015 18:15:00 +0200 Subject: [PATCH] [FEATURE]: getMap in dxf format --- src/server/CMakeLists.txt | 2 + src/server/qgshttprequesthandler.cpp | 1 - src/server/qgsserverstreamingdevice.cpp | 59 ++++++++ src/server/qgsserverstreamingdevice.h | 44 ++++++ src/server/qgswmsserver.cpp | 172 +++++++++++++++++++++++- src/server/qgswmsserver.h | 6 + 6 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 src/server/qgsserverstreamingdevice.cpp create mode 100644 src/server/qgsserverstreamingdevice.h diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 712bcfee987b..c7c63c061f0a 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -45,6 +45,7 @@ SET ( qgis_mapserv_SRCS qgswmsconfigparser.cpp qgswmsprojectparser.cpp qgsserverprojectparser.cpp + qgsserverstreamingdevice.cpp qgssldconfigparser.cpp qgsconfigparserutils.cpp ) @@ -160,6 +161,7 @@ INCLUDE_DIRECTORIES( ${QT_INCLUDE_DIR} ${QGIS_INCLUDE_DIR} ../core + ../core/dxf ../core/geometry ../core/raster ../core/symbology-ng diff --git a/src/server/qgshttprequesthandler.cpp b/src/server/qgshttprequesthandler.cpp index 11d996183a85..825c452f4aa3 100644 --- a/src/server/qgshttprequesthandler.cpp +++ b/src/server/qgshttprequesthandler.cpp @@ -131,7 +131,6 @@ void QgsHttpRequestHandler::sendHeaders() printf( it.value().toLocal8Bit() ); printf( "\n" ); } - printf( "\n" ); } printf( "\n" ); mHeaders.clear(); diff --git a/src/server/qgsserverstreamingdevice.cpp b/src/server/qgsserverstreamingdevice.cpp new file mode 100644 index 000000000000..e139bf3b798b --- /dev/null +++ b/src/server/qgsserverstreamingdevice.cpp @@ -0,0 +1,59 @@ +/*************************************************************************** + qgsserverstreamingdevice.cpp + ------------------------------------------------------------------- +Date : 25 May 2015 +Copyright : (C) 2015 by Marco Hugentobler +email : marco.hugentobler at sourcepole dot com + *************************************************************************** + * * + * 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 "qgsserverstreamingdevice.h" +#include "qgsrequesthandler.h" + +QgsServerStreamingDevice::QgsServerStreamingDevice( const QString& formatName, QgsRequestHandler* rh, QObject* parent ): QIODevice( parent ), mFormatName( formatName ), mRequestHandler( rh ) +{ +} + +QgsServerStreamingDevice::QgsServerStreamingDevice(): QIODevice( 0 ), mRequestHandler( 0 ) +{ + +} + +QgsServerStreamingDevice::~QgsServerStreamingDevice() +{ +} + +bool QgsServerStreamingDevice::open( OpenMode mode ) +{ + if( !mRequestHandler || mode != QIODevice::WriteOnly ) + { + return false; + } + + mRequestHandler->setHeader( "Content-Type", mFormatName ); + mRequestHandler->sendResponse(); + return QIODevice::open( mode ); +} + +void QgsServerStreamingDevice::close() +{ + QIODevice::close(); +} + +qint64 QgsServerStreamingDevice::writeData( const char * data, qint64 maxSize ) +{ + QByteArray ba( data, maxSize ); + mRequestHandler->setGetFeatureResponse( &ba ); + return maxSize; +} + +qint64 QgsServerStreamingDevice::readData( char * data, qint64 maxSize ) +{ + return -1; //reading not supported +} diff --git a/src/server/qgsserverstreamingdevice.h b/src/server/qgsserverstreamingdevice.h new file mode 100644 index 000000000000..fbec9466fbd2 --- /dev/null +++ b/src/server/qgsserverstreamingdevice.h @@ -0,0 +1,44 @@ +/*************************************************************************** + qgsserverstreamingdevice.h + ------------------------------------------------------------------- +Date : 25 May 2015 +Copyright : (C) 2015 by Marco Hugentobler +email : marco.hugentobler at sourcepole dot com + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef QGSSERVERSTREAMINGDEVICE_H +#define QGSSERVERSTREAMINGDEVICE_H + +#include + +class QgsRequestHandler; + +class QgsServerStreamingDevice: public QIODevice +{ + public: + QgsServerStreamingDevice( const QString& formatName, QgsRequestHandler* rh, QObject* parent = 0 ); + ~QgsServerStreamingDevice(); + + bool isSequential() const { return false; } + + bool open( OpenMode mode ); + void close(); + + protected: + QString mFormatName; + QgsRequestHandler* mRequestHandler; + + QgsServerStreamingDevice(); //default constructor forbidden + + qint64 writeData( const char * data, qint64 maxSize ); + qint64 readData ( char * data, qint64 maxSize ); +}; + +#endif // QGSSERVERSTREAMINGDEVICE_H diff --git a/src/server/qgswmsserver.cpp b/src/server/qgswmsserver.cpp index 2bfb8237b975..37cc44d0a8e6 100644 --- a/src/server/qgswmsserver.cpp +++ b/src/server/qgswmsserver.cpp @@ -18,6 +18,7 @@ #include "qgswmsserver.h" #include "qgscapabilitiescache.h" #include "qgscrscache.h" +#include "qgsdxfexport.h" #include "qgsfield.h" #include "qgsgeometry.h" #include "qgslayertree.h" @@ -46,6 +47,7 @@ #include "qgsogcutils.h" #include "qgsfeature.h" #include "qgseditorwidgetregistry.h" +#include "qgsserverstreamingdevice.h" #include #include @@ -158,6 +160,25 @@ void QgsWMSServer::executeRequest() //GetMap else if ( request.compare( "GetMap", Qt::CaseInsensitive ) == 0 ) { + //export as dxf + QString format = mParameters.value( "FORMAT" ); + if ( format.compare( "application/dxf", Qt::CaseInsensitive ) == 0 ) + { + try + { + getMapAsDxf(); + cleanupAfterRequest(); + return; + } + catch ( QgsMapServiceException& ex ) + { + QgsDebugMsg( "Caught exception during GetMap request" ); + mRequestHandler->setServiceException( ex ); + cleanupAfterRequest(); + return; + } + } + QImage* result = 0; try { @@ -446,7 +467,7 @@ QDomDocument QgsWMSServer::getCapabilities( QString version, bool fullProjectInf //wms:GetMap elem = doc.createElement( "GetMap"/*wms:GetMap*/ ); - appendFormats( doc, elem, QStringList() << "image/jpeg" << "image/png" << "image/png; mode=16bit" << "image/png; mode=8bit" << "image/png; mode=1bit" ); + appendFormats( doc, elem, QStringList() << "image/jpeg" << "image/png" << "image/png; mode=16bit" << "image/png; mode=8bit" << "image/png; mode=1bit" << "application/dxf" ); elem.appendChild( dcpTypeElement.cloneNode().toElement() ); //this is the same as for 'GetCapabilities' requestElement.appendChild( elem ); @@ -1311,6 +1332,76 @@ QImage* QgsWMSServer::getMap( HitTest* hitTest ) return theImage; } +void QgsWMSServer::getMapAsDxf() +{ + QgsServerStreamingDevice d( "application/dxf" , mRequestHandler ); + if ( !d.open( QIODevice::WriteOnly ) ) + { + throw QgsMapServiceException( "Internal server error", "Error opening output device for writing" ); + } + + QgsDxfExport dxf; + + //BBOX + bool bboxOk; + QgsRectangle extent = _parseBBOX( mParameters.value( "BBOX", "0,0,0,0" ), bboxOk ); + if ( !bboxOk ) + { + extent = QgsRectangle(); + } + dxf.setExtent( extent ); + + //get format options (for MODE,SCALE, LAYERATTRIBUTES ) + QMap formatOptionsMap; + readFormatOptions( formatOptionsMap ); + + QList< QPair > layers; + readDxfLayerSettings( layers, formatOptionsMap ); + dxf.addLayers( layers ); + + //MODE + QMap::const_iterator modeIt = formatOptionsMap.find( "MODE" ); + + QgsDxfExport::SymbologyExport se; + if ( modeIt == formatOptionsMap.constEnd() ) + { + se = QgsDxfExport::NoSymbology; + } + else + { + if ( modeIt->compare( "SymbolLayerSymbology", Qt::CaseInsensitive ) == 0 ) + { + se = QgsDxfExport::SymbolLayerSymbology; + } + else if ( modeIt->compare( "FeatureSymbology", Qt::CaseInsensitive ) == 0 ) + { + se = QgsDxfExport::FeatureSymbology; + } + else + { + se = QgsDxfExport::NoSymbology; + } + } + dxf.setSymbologyExport( se ); + + //SCALE + QMap::const_iterator scaleIt = formatOptionsMap.find( "SCALE" ); + if ( scaleIt != formatOptionsMap.constEnd() ) + { + dxf.setSymbologyScaleDenominator( scaleIt->toDouble() ); + } + + QString codec = "ISO-8859-1"; + QMap::const_iterator codecIt = formatOptionsMap.find( "CODEC" ); + if ( codecIt != formatOptionsMap.constEnd() ) + { + codec = formatOptionsMap.value( "CODEC" ); + } + + dxf.writeToFile( &d, codec ); + d.close(); +} + int QgsWMSServer::getFeatureInfo( QDomDocument& result, QString version ) { if ( !mMapRenderer || !mConfigParser ) @@ -3114,3 +3205,82 @@ QgsRectangle QgsWMSServer::featureInfoSearchRect( QgsVectorLayer* ml, QgsMapRend infoPoint.x() + mapUnitTolerance, infoPoint.y() + mapUnitTolerance ); return( mr->mapToLayerCoordinates( ml, mapRectangle ) ); } + +void QgsWMSServer::readFormatOptions( QMap& formatOptions ) const +{ + formatOptions.clear(); + QString fo = mParameters.value( "FORMAT_OPTIONS" ); + QStringList formatOptionsList = fo.split( ";" ); + QStringList::const_iterator optionsIt = formatOptionsList.constBegin(); + for ( ; optionsIt != formatOptionsList.constEnd(); ++optionsIt ) + { + int equalIdx = optionsIt->indexOf( ":" ); + if ( equalIdx > 0 && equalIdx < ( optionsIt->length() - 1 ) ) + { + formatOptions.insert( optionsIt->left( equalIdx ).toUpper(), optionsIt->right( optionsIt->length() - equalIdx - 1 ).toUpper() ); + } + } +} + +void QgsWMSServer::readDxfLayerSettings( QList< QPair >& layers, const QMap& formatOptionsMap ) const +{ + layers.clear(); + + QSet wfsLayers = QSet::fromList( mConfigParser->wfsLayerNames() ); + + QStringList layerAttributes; + QMap::const_iterator layerAttributesIt = formatOptionsMap.find( "LAYERATTRIBUTES" ); + if ( layerAttributesIt != formatOptionsMap.constEnd() ) + { + layerAttributes = formatOptionsMap.value( "LAYERATTRIBUTES" ).split( "," ); + } + + //LAYERS and STYLES + QStringList layerList, styleList; + if ( readLayersAndStyles( layerList, styleList ) != 0 ) + { + return; + } + + for ( int i = 0; i < layerList.size(); ++i ) + { + QString layerName = layerList.at( i ); + QString styleName; + if ( styleList.size() > i ) + { + styleName = styleList.at( i ); + } + + QList layerList = mConfigParser->mapLayerFromStyle( layerName, styleName ); + QList::const_iterator layerIt = layerList.constBegin(); + for ( ; layerIt != layerList.constEnd(); ++layerIt ) + { + if ( !( *layerIt ) ) + { + continue; + } + + //vector layer? + if (( *layerIt )->type() != QgsMapLayer::VectorLayer ) + { + continue; + } + + QgsVectorLayer* vlayer = static_cast( *layerIt ); + + int layerAttribute = -1; + if ( layerAttributes.size() > i ) + { + layerAttribute = vlayer->pendingFields().indexFromName( layerAttributes.at( i ) ); + } + + //only wfs layers are allowed to be published + if ( !wfsLayers.contains( vlayer->name() ) ) + { + continue; + } + + layers.append( qMakePair( vlayer, layerAttribute ) ); + } + } +} diff --git a/src/server/qgswmsserver.h b/src/server/qgswmsserver.h index a933ddd2c0a4..f874f0ee035b 100644 --- a/src/server/qgswmsserver.h +++ b/src/server/qgswmsserver.h @@ -84,6 +84,8 @@ class QgsWMSServer: public QgsOWSServer of the image object). If an instance to existing hit test structure is passed, instead of rendering it will fill the structure with symbols that would be used for rendering */ QImage* getMap( HitTest* hitTest = 0 ); + /**GetMap request with vector format output. This output is usually symbolized (difference to WFS GetFeature)*/ + void getMapAsDxf(); /**Returns an SLD file with the style of the requested layer. Exception is raised in case of troubles :-)*/ QDomDocument getStyle(); /**Returns an SLD file with the styles of the requested layers. Exception is raised in case of troubles :-)*/ @@ -254,6 +256,10 @@ class QgsWMSServer: public QgsOWSServer /**Gets layer search rectangle (depending on request parameter, layer type, map and layer crs)*/ QgsRectangle featureInfoSearchRect( QgsVectorLayer* ml, QgsMapRenderer* mr, const QgsRenderContext& rct, const QgsPoint& infoPoint ) const; + + /**Reads and extracts the different options in the FORMAT_OPTIONS parameter*/ + void readFormatOptions( QMap& formatOptions ) const; + void readDxfLayerSettings( QList< QPair >& layers, const QMap& formatOptionsMap ) const; }; #endif