[FEATURE]: possibility to export vector symbology (using ogr feature style)

This commit is contained in:
Marco Hugentobler 2013-01-29 09:45:30 +01:00
commit a00e413b5d
18 changed files with 782 additions and 79 deletions

View File

@ -168,9 +168,9 @@ class QgsSymbolLayerV2Utils
static QColor parseColor( QString colorStr );
/**Returns the line width scale factor depending on the unit and the paint device*/
static double lineWidthScaleFactor( QgsRenderContext& c, QgsSymbolV2::OutputUnit u );
static double lineWidthScaleFactor( const QgsRenderContext& c, QgsSymbolV2::OutputUnit u );
/**Returns scale factor painter units -> pixel dimensions*/
static double pixelSizeScaleFactor( QgsRenderContext& c, QgsSymbolV2::OutputUnit u );
static double pixelSizeScaleFactor( const QgsRenderContext& c, QgsSymbolV2::OutputUnit u );
/**Creates a render context for a pixel based device*/
static QgsRenderContext createRenderContext( QPainter* p );

View File

@ -82,6 +82,7 @@ INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_SOURCE_DIR}/../core/
${CMAKE_CURRENT_SOURCE_DIR}/../core/renderer
${CMAKE_CURRENT_SOURCE_DIR}/../core/raster
${CMAKE_CURRENT_SOURCE_DIR}/../core/symbology-ng
interpolation
${PROJ_INCLUDE_DIR}
${GEOS_INCLUDE_DIR}

View File

@ -62,6 +62,12 @@ QgsVectorLayerSaveAsDialog::QgsVectorLayerSaveAsDialog( long srsid, QWidget* par
mEncodingComboBox->setCurrentIndex( idx );
on_mFormatComboBox_currentIndexChanged( mFormatComboBox->currentIndex() );
//symbology export combo box
mSymbologyExportComboBox->addItem( tr( "No symbology" ), QgsVectorFileWriter::NoSymbology );
mSymbologyExportComboBox->addItem( tr( "Feature symbology" ), QgsVectorFileWriter::FeatureSymbology );
mSymbologyExportComboBox->addItem( tr( "Symbol layer symbology" ), QgsVectorFileWriter::SymbolLayerSymbology );
on_mSymbologyExportComboBox_currentIndexChanged( mSymbologyExportComboBox->currentText() );
}
QgsVectorLayerSaveAsDialog::~QgsVectorLayerSaveAsDialog()
@ -190,3 +196,24 @@ bool QgsVectorLayerSaveAsDialog::addToCanvas() const
{
return mAddToCanvas->isChecked();
}
int QgsVectorLayerSaveAsDialog::symbologyExport() const
{
return mSymbologyExportComboBox->itemData( mSymbologyExportComboBox->currentIndex() ).toInt();
}
double QgsVectorLayerSaveAsDialog::scaleDenominator() const
{
return mScaleSpinBox->value();
}
void QgsVectorLayerSaveAsDialog::on_mSymbologyExportComboBox_currentIndexChanged( const QString& text )
{
bool scaleEnabled = true;
if ( text == tr( "No symbology" ) )
{
scaleEnabled = false;
}
mScaleSpinBox->setEnabled( scaleEnabled );
mScaleLabel->setEnabled( scaleEnabled );
}

View File

@ -41,6 +41,12 @@ class QgsVectorLayerSaveAsDialog : public QDialog, private Ui::QgsVectorLayerSav
long crs() const;
bool skipAttributeCreation() const;
bool addToCanvas() const;
/**Returns type of symbology export.
0: No symbology
1: Feature symbology
2: Symbol level symbology*/
int symbologyExport() const;
double scaleDenominator() const;
private slots:
void on_mFormatComboBox_currentIndexChanged( int idx );
@ -48,6 +54,7 @@ class QgsVectorLayerSaveAsDialog : public QDialog, private Ui::QgsVectorLayerSav
void on_browseFilename_clicked();
void on_browseCRS_clicked();
void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); }
void on_mSymbologyExportComboBox_currentIndexChanged( const QString& text );
void accept();
private:

View File

@ -4268,7 +4268,9 @@ void QgisApp::saveAsVectorFileGeneral( bool saveOnlySelection )
&errorMessage,
datasourceOptions, dialog->layerOptions(),
dialog->skipAttributeCreation(),
&newFilename );
&newFilename,
( QgsVectorFileWriter::SymbologyExport )( dialog->symbologyExport() ),
dialog->scaleDenominator() );
QApplication::restoreOverrideCursor();

View File

@ -24,6 +24,8 @@
#include "qgsmessagelog.h"
#include "qgscoordinatereferencesystem.h"
#include "qgsvectorfilewriter.h"
#include "qgsrendererv2.h"
#include "qgssymbollayerv2.h"
#include <QFile>
#include <QSettings>
@ -61,12 +63,14 @@ QgsVectorFileWriter::QgsVectorFileWriter(
const QString& driverName,
const QStringList &datasourceOptions,
const QStringList &layerOptions,
QString *newFilename
QString *newFilename,
SymbologyExport symbologyExport
)
: mDS( NULL )
, mLayer( NULL )
, mGeom( NULL )
, mError( NoError )
, mSymbologyExport( symbologyExport )
{
QString vectorFileName = theVectorFileName;
QString fileEncoding = theFileEncoding;
@ -428,24 +432,84 @@ QString QgsVectorFileWriter::errorMessage()
return mErrorMessage;
}
bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
bool QgsVectorFileWriter::addFeature( QgsFeature& feature, QgsFeatureRendererV2* renderer, QGis::UnitType outputUnit )
{
// create the feature
OGRFeatureH poFeature = createFeature( feature );
//add OGR feature style type
if ( mSymbologyExport != NoSymbology && renderer )
{
//SymbolLayerSymbology: concatenate ogr styles of all symbollayers
QgsSymbolV2List symbols = renderer->symbolsForFeature( feature );
QString styleString;
QString currentStyle;
QgsSymbolV2List::const_iterator symbolIt = symbols.constBegin();
for ( ; symbolIt != symbols.constEnd(); ++symbolIt )
{
int nSymbolLayers = ( *symbolIt )->symbolLayerCount();
for ( int i = 0; i < nSymbolLayers; ++i )
{
/*QMap< QgsSymbolLayerV2*, QString >::const_iterator it = mSymbolLayerTable.find( (*symbolIt)->symbolLayer( i ) );
if( it == mSymbolLayerTable.constEnd() )
{
continue;
}*/
double mmsf = mmScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), outputUnit );
double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), outputUnit );
currentStyle = ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf );//"@" + it.value();
if ( mSymbologyExport == FeatureSymbology )
{
if ( symbolIt != symbols.constBegin() || i != 0 )
{
styleString.append( ";" );
}
styleString.append( currentStyle );
}
else if ( mSymbologyExport == SymbolLayerSymbology )
{
OGR_F_SetStyleString( poFeature, currentStyle.toLocal8Bit().data() );
if ( !writeFeature( mLayer, poFeature ) )
{
return false;
}
}
}
}
OGR_F_SetStyleString( poFeature, styleString.toLocal8Bit().data() );
}
if ( mSymbologyExport == NoSymbology || mSymbologyExport == FeatureSymbology )
{
if ( !writeFeature( mLayer, poFeature ) )
{
return false;
}
}
OGR_F_Destroy( poFeature );
return true;
}
OGRFeatureH QgsVectorFileWriter::createFeature( QgsFeature& feature )
{
OGRFeatureH poFeature = OGR_F_Create( OGR_L_GetLayerDefn( mLayer ) );
qint64 fid = FID_TO_NUMBER( feature.id() );
if ( fid > std::numeric_limits<int>::max() )
{
QgsDebugMsg( QString( "feature id %1 too large." ).arg( fid ) );
}
OGRErr err = OGR_F_SetFID( poFeature, static_cast<long>( fid ) );
if ( err != OGRERR_NONE )
{
QgsDebugMsg( QString( "Failed to set feature id to %1: %2 (OGR error: %3)" )
.arg( feature.id() )
.arg( err ).arg( CPLGetLastErrorMsg() )
);
OGRErr err = OGR_F_SetFID( poFeature, static_cast<long>( fid ) );
if ( err != OGRERR_NONE )
{
QgsDebugMsg( QString( "Failed to set feature id to %1: %2 (OGR error: %3)" )
.arg( feature.id() )
.arg( err ).arg( CPLGetLastErrorMsg() )
);
}
}
// attribute handling
@ -554,21 +618,19 @@ bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
OGR_F_SetGeometry( poFeature, mGeom );
}
}
return poFeature;
}
// put the created feature to layer
if ( OGR_L_CreateFeature( mLayer, poFeature ) != OGRERR_NONE )
bool QgsVectorFileWriter::writeFeature( OGRLayerH layer, OGRFeatureH feature )
{
if ( OGR_L_CreateFeature( layer, feature ) != OGRERR_NONE )
{
mErrorMessage = QObject::tr( "Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
mError = ErrFeatureWriteFailed;
QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
OGR_F_Destroy( poFeature );
OGR_F_Destroy( feature );
return false;
}
OGR_F_Destroy( poFeature );
return true;
}
@ -596,7 +658,9 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
const QStringList &datasourceOptions,
const QStringList &layerOptions,
bool skipAttributeCreation,
QString *newFilename )
QString *newFilename,
SymbologyExport symbologyExport,
double symbologyScale )
{
QgsDebugMsg( "fileName = " + fileName );
const QgsCoordinateReferenceSystem* outputCRS;
@ -620,7 +684,8 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
outputCRS = &layer->crs();
}
QgsVectorFileWriter* writer =
new QgsVectorFileWriter( fileName, fileEncoding, skipAttributeCreation ? QgsFields() : layer->pendingFields(), layer->wkbType(), outputCRS, driverName, datasourceOptions, layerOptions, newFilename );
new QgsVectorFileWriter( fileName, fileEncoding, skipAttributeCreation ? QgsFields() : layer->pendingFields(), layer->wkbType(), outputCRS, driverName, datasourceOptions, layerOptions, newFilename, symbologyExport );
writer->setSymbologyScaleDenominator( symbologyScale );
if ( newFilename )
{
@ -642,6 +707,20 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
errorMessage->clear();
}
QgsAttributeList allAttr = skipAttributeCreation ? QgsAttributeList() : layer->pendingAllAttributesList();
QgsFeature fet;
//add possible attributes needed by renderer
writer->addRendererAttributes( layer, allAttr );
QgsFeatureRequest req;
if ( layer->wkbType() == QGis::WKBNoGeometry )
{
req.setFlags( QgsFeatureRequest::NoGeometry );
}
req.setSubsetOfAttributes( allAttr );
QgsFeatureIterator fit = layer->getFeatures( req );
const QgsFeatureIds& ids = layer->selectedFeaturesIds();
// Create our transform
@ -656,18 +735,37 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
shallTransform = false;
}
//create symbol table if needed
if ( writer->symbologyExport() != NoSymbology )
{
//writer->createSymbolLayerTable( layer, writer->mDS );
}
if ( writer->symbologyExport() == SymbolLayerSymbology && layer->isUsingRendererV2() )
{
QgsFeatureRendererV2* r = layer->rendererV2();
if ( r->capabilities() & QgsFeatureRendererV2::SymbolLevels
&& r->usingSymbolLevels() )
{
QgsVectorFileWriter::WriterError error = writer->exportFeaturesSymbolLevels( layer, fit, ct, errorMessage );
delete writer;
delete ct;
return ( error == NoError ) ? NoError : ErrFeatureWriteFailed;
}
}
int n = 0, errors = 0;
QgsFeatureRequest req;
if ( layer->wkbType() == QGis::WKBNoGeometry )
req.setFlags( QgsFeatureRequest::NoGeometry );
if ( skipAttributeCreation )
req.setSubsetOfAttributes( QgsAttributeList() );
//unit type
QGis::UnitType mapUnits = layer->crs().mapUnits();
if ( ct )
{
mapUnits = ct->destCRS().mapUnits();
}
QgsFeatureIterator fit = layer->getFeatures( req );
writer->startRender( layer );
// write all features
QgsFeature fet;
while ( fit.nextFeature( fet ) )
{
if ( onlySelected && !ids.contains( fet.id() ) )
@ -696,11 +794,12 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
return ErrProjection;
}
}
if ( skipAttributeCreation )
if ( allAttr.size() < 1 && skipAttributeCreation )
{
fet.initAttributes( 0 );
}
if ( !writer->addFeature( fet ) )
if ( !writer->addFeature( fet, layer->rendererV2(), mapUnits ) )
{
WriterError err = writer->hasError();
if ( err != NoError && errorMessage )
@ -727,6 +826,7 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
n++;
}
writer->stopRender( layer );
delete writer;
if ( shallTransform )
@ -1061,3 +1161,289 @@ bool QgsVectorFileWriter::driverMetadata( QString driverName, QString &longName,
return true;
}
void QgsVectorFileWriter::createSymbolLayerTable( QgsVectorLayer* vl, const QgsCoordinateTransform* ct, OGRDataSourceH ds )
{
if ( !vl || !ds )
{
return;
}
if ( !vl->isUsingRendererV2() )
{
return;
}
QgsFeatureRendererV2* renderer = vl->rendererV2();
if ( !renderer )
{
return;
}
//unit type
QGis::UnitType mapUnits = vl->crs().mapUnits();
if ( ct )
{
mapUnits = ct->destCRS().mapUnits();
}
mSymbolLayerTable.clear();
OGRStyleTableH ogrStyleTable = OGR_STBL_Create();
OGRStyleMgrH styleManager = OGR_SM_Create( ogrStyleTable );
//get symbols
int nTotalLevels = 0;
QgsSymbolV2List symbolList = renderer->symbols();
QgsSymbolV2List::iterator symbolIt = symbolList.begin();
for ( ; symbolIt != symbolList.end(); ++symbolIt )
{
double mmsf = mmScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits );
double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits );
int nLevels = ( *symbolIt )->symbolLayerCount();
for ( int i = 0; i < nLevels; ++i )
{
mSymbolLayerTable.insert(( *symbolIt )->symbolLayer( i ), QString::number( nTotalLevels ) );
OGR_SM_AddStyle( styleManager, QString::number( nTotalLevels ).toLocal8Bit(),
( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf ).toLocal8Bit() );
++nTotalLevels;
}
}
OGR_DS_SetStyleTableDirectly( ds, ogrStyleTable );
}
QgsVectorFileWriter::WriterError QgsVectorFileWriter::exportFeaturesSymbolLevels( QgsVectorLayer* layer, QgsFeatureIterator& fit,
const QgsCoordinateTransform* ct, QString* errorMessage )
{
if ( !layer || !layer->isUsingRendererV2() )
{
//return error
}
QgsFeatureRendererV2* renderer = layer->rendererV2();
if ( !renderer )
{
//return error
}
QHash< QgsSymbolV2*, QList<QgsFeature> > features;
//unit type
QGis::UnitType mapUnits = layer->crs().mapUnits();
if ( ct )
{
mapUnits = ct->destCRS().mapUnits();
}
startRender( layer );
//fetch features
QgsFeature fet;
QgsSymbolV2* featureSymbol = 0;
while ( fit.nextFeature( fet ) )
{
if ( ct )
{
try
{
if ( fet.geometry() )
{
fet.geometry()->transform( *ct );
}
}
catch ( QgsCsException &e )
{
delete ct;
QString msg = QObject::tr( "Failed to transform, writing stopped. (Exception: %1)" )
.arg( e.what() );
QgsLogger::warning( msg );
if ( errorMessage )
*errorMessage = msg;
return ErrProjection;
}
}
featureSymbol = renderer->symbolForFeature( fet );
if ( !featureSymbol )
{
continue;
}
QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator it = features.find( featureSymbol );
if ( it == features.end() )
{
it = features.insert( featureSymbol, QList<QgsFeature>() );
}
it.value().append( fet );
}
//find out order
QgsSymbolV2LevelOrder levels;
QgsSymbolV2List symbols = renderer->symbols();
for ( int i = 0; i < symbols.count(); i++ )
{
QgsSymbolV2* sym = symbols[i];
for ( int j = 0; j < sym->symbolLayerCount(); j++ )
{
int level = sym->symbolLayer( j )->renderingPass();
if ( level < 0 || level >= 1000 ) // ignore invalid levels
continue;
QgsSymbolV2LevelItem item( sym, j );
while ( level >= levels.count() ) // append new empty levels
levels.append( QgsSymbolV2Level() );
levels[level].append( item );
}
}
int nErrors = 0;
int nTotalFeatures = 0;
//export symbol layers and symbology
for ( int l = 0; l < levels.count(); l++ )
{
QgsSymbolV2Level& level = levels[l];
for ( int i = 0; i < level.count(); i++ )
{
QgsSymbolV2LevelItem& item = level[i];
QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator levelIt = features.find( item.symbol() );
if ( levelIt == features.end() )
{
++nErrors;
continue;
}
double mmsf = mmScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits );
double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits );
int llayer = item.layer();
QList<QgsFeature>& featureList = levelIt.value();
QList<QgsFeature>::iterator featureIt = featureList.begin();
for ( ; featureIt != featureList.end(); ++featureIt )
{
++nTotalFeatures;
OGRFeatureH ogrFeature = createFeature( *featureIt );
if ( !ogrFeature )
{
++nErrors;
continue;
}
QString styleString = levelIt.key()->symbolLayer( llayer )->ogrFeatureStyle( mmsf, musf );
if ( !styleString.isEmpty() )
{
OGR_F_SetStyleString( ogrFeature, styleString.toLocal8Bit().data() );
if ( ! writeFeature( mLayer, ogrFeature ) )
{
++nErrors;
}
}
OGR_F_Destroy( ogrFeature );
}
}
}
stopRender( layer );
if ( nErrors > 0 && errorMessage )
{
*errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( nTotalFeatures - nErrors ).arg( nTotalFeatures );
}
return ( nErrors > 0 ) ? QgsVectorFileWriter::ErrFeatureWriteFailed : QgsVectorFileWriter::NoError;
}
double QgsVectorFileWriter::mmScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits )
{
if ( symbolUnits == QgsSymbolV2::MM )
{
return 1.0;
}
else
{
//conversion factor map units -> mm
if ( mapUnits == QGis::Meters )
{
return 1000 / scaleDenominator;
}
}
return 1.0; //todo: map units
}
double QgsVectorFileWriter::mapUnitScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits )
{
if ( symbolUnits == QgsSymbolV2::MapUnit )
{
return 1.0;
}
else
{
if ( symbolUnits == QgsSymbolV2::MM && mapUnits == QGis::Meters )
{
return scaleDenominator / 1000;
}
}
return 1.0;
}
QgsRenderContext QgsVectorFileWriter::renderContext() const
{
QgsRenderContext context;
context.setRendererScale( mSymbologyScaleDenominator );
return context;
}
void QgsVectorFileWriter::startRender( QgsVectorLayer* vl ) const
{
QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
if ( !renderer )
{
return;
}
QgsRenderContext ctx = renderContext();
renderer->startRender( ctx, vl );
}
void QgsVectorFileWriter::stopRender( QgsVectorLayer* vl ) const
{
QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
if ( !renderer )
{
return;
}
QgsRenderContext ctx = renderContext();
renderer->stopRender( ctx );
}
QgsFeatureRendererV2* QgsVectorFileWriter::symbologyRenderer( QgsVectorLayer* vl ) const
{
if ( mSymbologyExport == NoSymbology )
{
return 0;
}
if ( !vl || !vl->isUsingRendererV2() )
{
return 0;
}
return vl->rendererV2();
}
void QgsVectorFileWriter::addRendererAttributes( QgsVectorLayer* vl, QgsAttributeList& attList )
{
QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
if ( renderer )
{
QList<QString> rendererAttributes = renderer->usedAttributes();
for ( int i = 0; i < rendererAttributes.size(); ++i )
{
int index = vl->fieldNameIndex( rendererAttributes.at( i ) );
if ( index != -1 )
{
attList.push_back( vl->fieldNameIndex( rendererAttributes.at( i ) ) );
}
}
}
}

View File

@ -21,13 +21,16 @@
#include "qgsvectorlayer.h"
#include "qgsfield.h"
#include "qgssymbolv2.h"
#include <QPair>
typedef void *OGRDataSourceH;
typedef void *OGRLayerH;
typedef void *OGRGeometryH;
typedef void *OGRFeatureH;
class QgsSymbolLayerV2;
class QTextCodec;
/** \ingroup core
@ -56,6 +59,14 @@ class CORE_EXPORT QgsVectorFileWriter
ErrInvalidLayer, // added in 2.0
};
//added in 2.0
enum SymbologyExport
{
NoSymbology = 0, //export only data
FeatureSymbology, //Keeps the number of features and export symbology per feature
SymbolLayerSymbology //Exports one feature per symbol layer (considering symbol levels)
};
/** Write contents of vector layer to an (OGR supported) vector formt
@note: this method was added in version 1.5
@param layer layer to write
@ -81,7 +92,9 @@ class CORE_EXPORT QgsVectorFileWriter
const QStringList &datasourceOptions = QStringList(), // added in 1.6
const QStringList &layerOptions = QStringList(), // added in 1.6
bool skipAttributeCreation = false, // added in 1.6
QString *newFilename = 0 // added in 1.9
QString *newFilename = 0, // added in 1.9
SymbologyExport symbologyExport = NoSymbology, //added in 2.0
double symbologyScale = 1.0 // added in 2.0
);
/** create shapefile and initialize it */
@ -93,7 +106,8 @@ class CORE_EXPORT QgsVectorFileWriter
const QString& driverName = "ESRI Shapefile",
const QStringList &datasourceOptions = QStringList(), // added in 1.6
const QStringList &layerOptions = QStringList(), // added in 1.6
QString *newFilename = 0 // added in 1.9
QString *newFilename = 0, // added in 1.9
SymbologyExport symbologyExport = NoSymbology//added in 2.0
);
/**Returns map with format filter string as key and OGR format key as value*/
@ -120,7 +134,7 @@ class CORE_EXPORT QgsVectorFileWriter
QString errorMessage();
/** add feature to the currently opened shapefile */
bool addFeature( QgsFeature& feature );
bool addFeature( QgsFeature& feature, QgsFeatureRendererV2* renderer = 0, QGis::UnitType outputUnit = QGis::Meters );
//! @note not available in python bindings
QMap<int, int> attrIdxToOgrIdx() { return mAttrIdxToOgrIdx; }
@ -134,6 +148,12 @@ class CORE_EXPORT QgsVectorFileWriter
*/
static bool deleteShapeFile( QString theFileName );
SymbologyExport symbologyExport() const { return mSymbologyExport; }
void setSymbologyExport( SymbologyExport symExport ) { mSymbologyExport = symExport; }
double symbologyScaleDenominator() const { return mSymbologyScaleDenominator; }
void setSymbologyScaleDenominator( double d ) { mSymbologyScaleDenominator = d; }
protected:
//! @note not available in python bindings
OGRGeometryH createEmptyGeometry( QGis::WkbType wkbType );
@ -156,8 +176,30 @@ class CORE_EXPORT QgsVectorFileWriter
/** map attribute indizes to OGR field indexes */
QMap<int, int> mAttrIdxToOgrIdx;
SymbologyExport mSymbologyExport;
QMap< QgsSymbolLayerV2*, QString > mSymbolLayerTable;
/**Scale for symbology export (e.g. for symbols units in map units)*/
double mSymbologyScaleDenominator;
private:
static bool driverMetadata( QString driverName, QString &longName, QString &trLongName, QString &glob, QString &ext );
void createSymbolLayerTable( QgsVectorLayer* vl, const QgsCoordinateTransform* ct, OGRDataSourceH ds );
OGRFeatureH createFeature( QgsFeature& feature );
bool writeFeature( OGRLayerH layer, OGRFeatureH feature );
/**Writes features considering symbol level order*/
WriterError exportFeaturesSymbolLevels( QgsVectorLayer* layer, QgsFeatureIterator& fit, const QgsCoordinateTransform* ct, QString* errorMessage = 0 );
double mmScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits );
double mapUnitScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits );
QgsRenderContext renderContext() const;
void startRender( QgsVectorLayer* vl ) const;
void stopRender( QgsVectorLayer* vl ) const;
QgsFeatureRendererV2* symbologyRenderer( QgsVectorLayer* vl ) const;
/**Adds attributes needed for classification*/
void addRendererAttributes( QgsVectorLayer* vl, QgsAttributeList& attList );
};
#endif

View File

@ -175,6 +175,17 @@ void QgsSimpleFillSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element,
QgsSymbolLayerV2Utils::createDisplacementElement( doc, symbolizerElem, mOffset );
}
QString QgsSimpleFillSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
{
//brush
QString symbolStyle;
symbolStyle.append( QgsSymbolLayerV2Utils::ogrFeatureStyleBrush( mColor ) );
symbolStyle.append( ";" );
//pen
symbolStyle.append( QgsSymbolLayerV2Utils::ogrFeatureStylePen( mBorderWidth, mmScaleFactor, mapUnitScaleFactor, mBorderColor ) );
return symbolStyle;
}
QgsSymbolLayerV2* QgsSimpleFillSymbolLayerV2::createFromSld( QDomElement &element )
{
QgsDebugMsg( "Entered." );
@ -907,6 +918,21 @@ void QgsLinePatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &eleme
}
}
QString QgsLinePatternFillSymbolLayer::ogrFeatureStyle( double widthScaleFactor ) const
{
QString featureStyle;
featureStyle.append( "Brush(" );
featureStyle.append( QString( "fc:%1" ).arg( mColor.name() ) );
featureStyle.append( QString( ",bc:%1" ).arg( "#00000000" ) ); //transparent background
featureStyle.append( ",id:\"ogr-brush-2\"" );
featureStyle.append( QString( ",a:%1" ).arg( mLineAngle ) );
featureStyle.append( QString( ",s:%1" ).arg( mLineWidth * widthScaleFactor ) );
featureStyle.append( ",dx:0mm" );
featureStyle.append( QString( ",dy:%1mm" ).arg( mDistance * widthScaleFactor ) );
featureStyle.append( ")" );
return featureStyle;
}
QgsSymbolLayerV2* QgsLinePatternFillSymbolLayer::createFromSld( QDomElement &element )
{
QgsDebugMsg( "Entered." );

View File

@ -57,6 +57,8 @@ class CORE_EXPORT QgsSimpleFillSymbolLayerV2 : public QgsFillSymbolLayerV2
void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
QString ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const;
Qt::BrushStyle brushStyle() const { return mBrushStyle; }
void setBrushStyle( Qt::BrushStyle style ) { mBrushStyle = style; }
@ -189,6 +191,8 @@ class CORE_EXPORT QgsLinePatternFillSymbolLayer: public QgsImageFillSymbolLayer
void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
QString ogrFeatureStyle( double widthScaleFactor ) const;
//getters and setters
void setLineAngle( double a ) { mLineAngle = a; }
double lineAngle() const { return mLineAngle; }

View File

@ -195,6 +195,21 @@ void QgsSimpleLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element,
}
}
QString QgsSimpleLineSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
{
if ( mUseCustomDashPattern )
{
return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor,
mPen.color(), mPenJoinStyle,
mPenCapStyle, mOffset, &mCustomDashVector );
}
else
{
return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor, mPen.color(), mPenJoinStyle,
mPenCapStyle, mOffset );
}
}
QgsSymbolLayerV2* QgsSimpleLineSymbolLayerV2::createFromSld( QDomElement &element )
{
QgsDebugMsg( "Entered." );

View File

@ -56,6 +56,8 @@ class CORE_EXPORT QgsSimpleLineSymbolLayerV2 : public QgsLineSymbolLayerV2
void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
QString ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const;
// new stuff
Qt::PenStyle penStyle() const { return mPenStyle; }

View File

@ -480,6 +480,66 @@ void QgsSimpleMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElemen
QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
}
QString QgsSimpleMarkerSymbolLayerV2::ogrFeatureStyle( double widthScaleFactor ) const
{
#if 0
QString ogrType = "3"; //default is circle
if ( mName == "square" )
{
ogrType = "5";
}
else if ( mName == "triangle" )
{
ogrType = "7";
}
else if ( mName == "star" )
{
ogrType = "9";
}
else if ( mName == "circle" )
{
ogrType = "3";
}
else if ( mName == "cross" )
{
ogrType = "0";
}
else if ( mName == "x" || mName == "cross2" )
{
ogrType = "1";
}
else if ( mName == "line" )
{
ogrType = "10";
}
QString ogrString;
ogrString.append( "SYMBOL(" );
ogrString.append( "id:" );
ogrString.append( "\"" );
ogrString.append( "ogr-sym-" );
ogrString.append( ogrType );
ogrString.append( "\"" );
ogrString.append( ",c:" );
ogrString.append( mColor.name() );
ogrString.append( ",o:" );
ogrString.append( mBorderColor.name() );
ogrString.append( QString( ",s:%1mm" ).arg( mSize ) );
ogrString.append( ")" );
return ogrString;
#endif //0
QString ogrString;
ogrString.append( "PEN(" );
ogrString.append( "c:" );
ogrString.append( mColor.name() );
ogrString.append( ",w:" );
ogrString.append( QString::number( mSize ) );
ogrString.append( "mm" );
ogrString.append( ")" );
return ogrString;
}
QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::createFromSld( QDomElement &element )
{
QgsDebugMsg( "Entered." );

View File

@ -62,6 +62,8 @@ class CORE_EXPORT QgsSimpleMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
void writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
QString ogrFeatureStyle( double widthScaleFactor ) const;
QString name() const { return mName; }
void setName( QString name ) { mName = name; }

View File

@ -54,6 +54,8 @@ class CORE_EXPORT QgsSymbolLayerV2
virtual void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{ Q_UNUSED( props ); element.appendChild( doc.createComment( QString( "SymbolLayerV2 %1 not implemented yet" ).arg( layerType() ) ) ); }
virtual QString ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const { Q_UNUSED( mmScaleFactor ); Q_UNUSED( mapUnitScaleFactor ); return QString(); }
virtual QgsStringMap properties() const = 0;
virtual void drawPreviewIcon( QgsSymbolV2RenderContext& context, QSize size ) = 0;

View File

@ -2095,6 +2095,90 @@ void QgsSymbolLayerV2Utils::labelTextToSld( QDomDocument &doc, QDomElement &elem
}
}
QString QgsSymbolLayerV2Utils::ogrFeatureStylePen( double width, double mmScaleFactor, double mapUnitScaleFactor, const QColor& c,
Qt::PenJoinStyle joinStyle,
Qt::PenCapStyle capStyle,
double offset,
const QVector<qreal>* dashPattern )
{
QString penStyle;
penStyle.append( "PEN(" );
penStyle.append( "c:" );
penStyle.append( c.name() );
penStyle.append( ",w:" );
//dxf driver writes ground units as mm? Should probably be changed in ogr
penStyle.append( QString::number( width * mmScaleFactor ) );
penStyle.append( "mm" );
//dash dot vector
if ( dashPattern && dashPattern->size() > 0 )
{
penStyle.append( ",p:\"" );
QVector<qreal>::const_iterator pIt = dashPattern->constBegin();
for ( ; pIt != dashPattern->constEnd(); ++pIt )
{
if ( pIt != dashPattern->constBegin() )
{
penStyle.append( " " );
}
penStyle.append( QString::number( *pIt * mapUnitScaleFactor ) );
penStyle.append( "g" );
}
penStyle.append( "\"" );
}
//cap
penStyle.append( ",cap:" );
switch ( capStyle )
{
case Qt::SquareCap:
penStyle.append( "p" );
break;
case Qt::RoundCap:
penStyle.append( "r" );
break;
case Qt::FlatCap:
default:
penStyle.append( "b" );
}
//join
penStyle.append( ",j:" );
switch ( joinStyle )
{
case Qt::BevelJoin:
penStyle.append( "b" );
break;
case Qt::RoundJoin:
penStyle.append( "r" );
break;
case Qt::MiterJoin:
default:
penStyle.append( "m" );
}
//offset
if ( !doubleNear( offset, 0.0 ) )
{
penStyle.append( ",dp:" );
penStyle.append( QString::number( offset * mapUnitScaleFactor ) );
penStyle.append( "g" );
}
penStyle.append( ")" );
return penStyle;
}
QString QgsSymbolLayerV2Utils::ogrFeatureStyleBrush( const QColor& fillColor )
{
QString brushStyle;
brushStyle.append( "BRUSH(" );
brushStyle.append( "fc:" );
brushStyle.append( fillColor.name() );
brushStyle.append( ")" );
return brushStyle;
}
void QgsSymbolLayerV2Utils::createGeometryElement( QDomDocument &doc, QDomElement &element, QString geomFunc )
{
if ( geomFunc.isEmpty() )
@ -2454,7 +2538,7 @@ QColor QgsSymbolLayerV2Utils::parseColor( QString colorStr )
return QColor( p[0].toInt(), p[1].toInt(), p[2].toInt() );
}
double QgsSymbolLayerV2Utils::lineWidthScaleFactor( QgsRenderContext& c, QgsSymbolV2::OutputUnit u )
double QgsSymbolLayerV2Utils::lineWidthScaleFactor( const QgsRenderContext& c, QgsSymbolV2::OutputUnit u )
{
if ( u == QgsSymbolV2::MM )
@ -2475,7 +2559,7 @@ double QgsSymbolLayerV2Utils::lineWidthScaleFactor( QgsRenderContext& c, QgsSymb
}
}
double QgsSymbolLayerV2Utils::pixelSizeScaleFactor( QgsRenderContext& c, QgsSymbolV2::OutputUnit u )
double QgsSymbolLayerV2Utils::pixelSizeScaleFactor( const QgsRenderContext& c, QgsSymbolV2::OutputUnit u )
{
if ( u == QgsSymbolV2::MM )
{

View File

@ -164,6 +164,18 @@ class CORE_EXPORT QgsSymbolLayerV2Utils
static void labelTextToSld( QDomDocument &doc, QDomElement &element, QString label,
QFont font, QColor color = QColor(), double size = -1 );
/**Create ogr feature style string for pen
@param width linewidth in mm
@param c line color*/
static QString ogrFeatureStylePen( double width, double mmScaleFactor, double mapUnitsScaleFactor, const QColor& c,
Qt::PenJoinStyle joinStyle = Qt::MiterJoin,
Qt::PenCapStyle capStyle = Qt::FlatCap,
double offset = 0.0,
const QVector<qreal>* dashPattern = 0 );
/**Create ogr feature syle string for brush
@param fillColr fill color*/
static QString ogrFeatureStyleBrush( const QColor& fillColr );
static void createRotationElement( QDomDocument &doc, QDomElement &element, QString rotationFunc );
static bool rotationFromSldElement( QDomElement &element, QString &rotationFunc );
@ -203,9 +215,9 @@ class CORE_EXPORT QgsSymbolLayerV2Utils
static QColor parseColor( QString colorStr );
/**Returns the line width scale factor depending on the unit and the paint device*/
static double lineWidthScaleFactor( QgsRenderContext& c, QgsSymbolV2::OutputUnit u );
static double lineWidthScaleFactor( const QgsRenderContext& c, QgsSymbolV2::OutputUnit u );
/**Returns scale factor painter units -> pixel dimensions*/
static double pixelSizeScaleFactor( QgsRenderContext& c, QgsSymbolV2::OutputUnit u );
static double pixelSizeScaleFactor( const QgsRenderContext& c, QgsSymbolV2::OutputUnit u );
/**Creates a render context for a pixel based device*/
static QgsRenderContext createRenderContext( QPainter* p );

View File

@ -11,6 +11,7 @@ QT4_WRAP_CPP(OGR_MOC_SRCS ${OGR_MOC_HDRS})
INCLUDE_DIRECTORIES(
.
../../core
${CMAKE_CURRENT_SOURCE_DIR}/../../core/symbology-ng
${GDAL_INCLUDE_DIR}
${GEOS_INCLUDE_DIR}
)

View File

@ -21,23 +21,40 @@
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="leCRS">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
<item row="6" column="2">
<widget class="QPushButton" name="browseCRS">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="3">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Encoding</string>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok</set>
<property name="buddy">
<cstring>mEncodingComboBox</cstring>
</property>
</widget>
</item>
<item row="5" column="0" rowspan="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>CRS</string>
</property>
<property name="buddy">
<cstring>leCRS</cstring>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<widget class="QComboBox" name="mEncodingComboBox"/>
</item>
<item row="7" column="0">
<widget class="QLabel" name="mSymbologyExportLabel">
<property name="text">
<string>Symbology export</string>
</property>
</widget>
</item>
@ -51,6 +68,9 @@
</property>
</widget>
</item>
<item row="7" column="1" colspan="2">
<widget class="QComboBox" name="mSymbologyExportComboBox"/>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="browseFilename">
<property name="enabled">
@ -61,25 +81,18 @@
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QPushButton" name="browseCRS">
<property name="text">
<string>Browse</string>
<item row="6" column="1">
<widget class="QLineEdit" name="leCRS">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<widget class="QComboBox" name="mEncodingComboBox"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Encoding</string>
</property>
<property name="buddy">
<cstring>mEncodingComboBox</cstring>
</property>
</widget>
<item row="5" column="1" colspan="2">
<widget class="QComboBox" name="mCRSSelection"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
@ -91,10 +104,20 @@
</property>
</widget>
</item>
<item row="10" column="0" colspan="3">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QComboBox" name="mFormatComboBox"/>
</item>
<item row="7" column="0" colspan="3">
<item row="9" column="0" colspan="3">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>OGR creation options</string>
@ -146,16 +169,23 @@
</layout>
</widget>
</item>
<item row="5" column="1" colspan="2">
<widget class="QComboBox" name="mCRSSelection"/>
</item>
<item row="5" column="0" rowspan="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>CRS</string>
<item row="8" column="1" colspan="2">
<widget class="QSpinBox" name="mScaleSpinBox">
<property name="prefix">
<string>1:</string>
</property>
<property name="buddy">
<cstring>leCRS</cstring>
<property name="maximum">
<number>999999999</number>
</property>
<property name="value">
<number>50000</number>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="mScaleLabel">
<property name="text">
<string>Scale</string>
</property>
</widget>
</item>