QGIS API Documentation  master-59fd5e0
src/core/symbology-ng/qgsfillsymbollayerv2.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002     qgsfillsymbollayerv2.cpp
00003     ---------------------
00004     begin                : November 2009
00005     copyright            : (C) 2009 by Martin Dobias
00006     email                : wonder dot sk at gmail dot com
00007  ***************************************************************************
00008  *                                                                         *
00009  *   This program is free software; you can redistribute it and/or modify  *
00010  *   it under the terms of the GNU General Public License as published by  *
00011  *   the Free Software Foundation; either version 2 of the License, or     *
00012  *   (at your option) any later version.                                   *
00013  *                                                                         *
00014  ***************************************************************************/
00015 #include "qgsfillsymbollayerv2.h"
00016 #include "qgsmarkersymbollayerv2.h"
00017 #include "qgssymbollayerv2utils.h"
00018 
00019 #include "qgsexpression.h"
00020 #include "qgsrendercontext.h"
00021 #include "qgsproject.h"
00022 #include "qgssvgcache.h"
00023 #include "qgslogger.h"
00024 
00025 #include <QPainter>
00026 #include <QFile>
00027 #include <QSvgRenderer>
00028 #include <QDomDocument>
00029 #include <QDomElement>
00030 
00031 QgsSimpleFillSymbolLayerV2::QgsSimpleFillSymbolLayerV2( QColor color, Qt::BrushStyle style, QColor borderColor, Qt::PenStyle borderStyle, double borderWidth )
00032     : mBrushStyle( style ), mBorderColor( borderColor ), mBorderStyle( borderStyle ), mBorderWidth( borderWidth ), mBorderWidthUnit( QgsSymbolV2::MM ),
00033     mOffsetUnit( QgsSymbolV2::MM )
00034 {
00035   mColor = color;
00036 }
00037 
00038 void QgsSimpleFillSymbolLayerV2::setOutputUnit( QgsSymbolV2::OutputUnit unit )
00039 {
00040   mBorderWidthUnit = unit;
00041   mOffsetUnit = unit;
00042 }
00043 
00044 QgsSymbolV2::OutputUnit QgsSimpleFillSymbolLayerV2::outputUnit() const
00045 {
00046   QgsSymbolV2::OutputUnit unit = mBorderWidthUnit;
00047   if ( mOffsetUnit != unit )
00048   {
00049     return QgsSymbolV2::Mixed;
00050   }
00051   return unit;
00052 }
00053 
00054 void QgsSimpleFillSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QBrush& brush, QPen& pen, QPen& selPen )
00055 {
00056   QgsExpression* colorExpression = expression( "color" );
00057   if ( colorExpression )
00058   {
00059     brush.setColor( QgsSymbolLayerV2Utils::decodeColor( colorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
00060   }
00061   QgsExpression* colorBorderExpression = expression( "color_border" );
00062   if ( colorBorderExpression )
00063   {
00064     pen.setColor( QgsSymbolLayerV2Utils::decodeColor( colorBorderExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
00065   }
00066   QgsExpression* widthBorderExpression = expression( "width_border" );
00067   if ( widthBorderExpression )
00068   {
00069     double width = widthBorderExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
00070     width *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mBorderWidthUnit );
00071     pen.setWidthF( width );
00072     selPen.setWidthF( width );
00073   }
00074 }
00075 
00076 
00077 QgsSymbolLayerV2* QgsSimpleFillSymbolLayerV2::create( const QgsStringMap& props )
00078 {
00079   QColor color = DEFAULT_SIMPLEFILL_COLOR;
00080   Qt::BrushStyle style = DEFAULT_SIMPLEFILL_STYLE;
00081   QColor borderColor = DEFAULT_SIMPLEFILL_BORDERCOLOR;
00082   Qt::PenStyle borderStyle = DEFAULT_SIMPLEFILL_BORDERSTYLE;
00083   double borderWidth = DEFAULT_SIMPLEFILL_BORDERWIDTH;
00084   QPointF offset;
00085 
00086   if ( props.contains( "color" ) )
00087     color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
00088   if ( props.contains( "style" ) )
00089     style = QgsSymbolLayerV2Utils::decodeBrushStyle( props["style"] );
00090   if ( props.contains( "color_border" ) )
00091     borderColor = QgsSymbolLayerV2Utils::decodeColor( props["color_border"] );
00092   if ( props.contains( "style_border" ) )
00093     borderStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["style_border"] );
00094   if ( props.contains( "width_border" ) )
00095     borderWidth = props["width_border"].toDouble();
00096   if ( props.contains( "offset" ) )
00097     offset = QgsSymbolLayerV2Utils::decodePoint( props["offset"] );
00098 
00099   QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( color, style, borderColor, borderStyle, borderWidth );
00100   sl->setOffset( offset );
00101   if ( props.contains( "border_width_unit" ) )
00102     sl->setBorderWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["border_width_unit"] ) );
00103   if ( props.contains( "offset_unit" ) )
00104     sl->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
00105 
00106   if ( props.contains( "color_expression" ) )
00107   {
00108     sl->setDataDefinedProperty( "color", props["color_expression"] );
00109   }
00110   if ( props.contains( "color_border_expression" ) )
00111   {
00112     sl->setDataDefinedProperty( "color_border", props["color_border_expression"] );
00113   }
00114   if ( props.contains( "width_border_expression" ) )
00115   {
00116     sl->setDataDefinedProperty( "width_border", props["width_border_expression"] );
00117   }
00118   return sl;
00119 }
00120 
00121 
00122 QString QgsSimpleFillSymbolLayerV2::layerType() const
00123 {
00124   return "SimpleFill";
00125 }
00126 
00127 void QgsSimpleFillSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
00128 {
00129   QColor fillColor = mColor;
00130   fillColor.setAlphaF( context.alpha() * mColor.alphaF() );
00131   mBrush = QBrush( fillColor, mBrushStyle );
00132 
00133   // scale brush content for printout
00134   double rasterScaleFactor = context.renderContext().rasterScaleFactor();
00135   if ( rasterScaleFactor != 1.0 )
00136   {
00137     mBrush.setMatrix( QMatrix().scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor ) );
00138   }
00139 
00140   QColor selColor = context.renderContext().selectionColor();
00141   QColor selPenColor = selColor == mColor ? selColor : mBorderColor;
00142   if ( ! selectionIsOpaque ) selColor.setAlphaF( context.alpha() );
00143   mSelBrush = QBrush( selColor );
00144   // N.B. unless a "selection line color" is implemented in addition to the "selection color" option
00145   // this would mean symbols with "no fill" look the same whether or not they are selected
00146   if ( selectFillStyle )
00147     mSelBrush.setStyle( mBrushStyle );
00148 
00149   QColor borderColor = mBorderColor;
00150   borderColor.setAlphaF( context.alpha() * mBorderColor.alphaF() );
00151   mPen = QPen( borderColor );
00152   mSelPen = QPen( selPenColor );
00153   mPen.setStyle( mBorderStyle );
00154   mPen.setWidthF( mBorderWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mBorderWidthUnit ) );
00155   prepareExpressions( context.layer() );
00156 }
00157 
00158 void QgsSimpleFillSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
00159 {
00160   Q_UNUSED( context );
00161 }
00162 
00163 void QgsSimpleFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
00164 {
00165   QPainter* p = context.renderContext().painter();
00166   if ( !p )
00167   {
00168     return;
00169   }
00170 
00171   applyDataDefinedSymbology( context, mBrush, mPen, mSelPen );
00172 
00173   p->setBrush( context.selected() ? mSelBrush : mBrush );
00174   p->setPen( mPen );
00175   p->setPen( context.selected() ? mSelPen : mPen );
00176 
00177   QPointF offset;
00178   if ( !mOffset.isNull() )
00179   {
00180     offset.setX( mOffset.x() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit ) );
00181     offset.setY( mOffset.y() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit ) );
00182     p->translate( offset );
00183   }
00184 
00185   _renderPolygon( p, points, rings );
00186 
00187   if ( !mOffset.isNull() )
00188   {
00189     p->translate( -offset );
00190   }
00191 }
00192 
00193 QgsStringMap QgsSimpleFillSymbolLayerV2::properties() const
00194 {
00195   QgsStringMap map;
00196   map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
00197   map["style"] = QgsSymbolLayerV2Utils::encodeBrushStyle( mBrushStyle );
00198   map["color_border"] = QgsSymbolLayerV2Utils::encodeColor( mBorderColor );
00199   map["style_border"] = QgsSymbolLayerV2Utils::encodePenStyle( mBorderStyle );
00200   map["width_border"] = QString::number( mBorderWidth );
00201   map["border_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mBorderWidthUnit );
00202   map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
00203   map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
00204   saveDataDefinedProperties( map );
00205   return map;
00206 }
00207 
00208 QgsSymbolLayerV2* QgsSimpleFillSymbolLayerV2::clone() const
00209 {
00210   QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( mColor, mBrushStyle, mBorderColor, mBorderStyle, mBorderWidth );
00211   sl->setOffset( mOffset );
00212   sl->setOffsetUnit( mOffsetUnit );
00213   sl->setBorderWidthUnit( mBorderWidthUnit );
00214   copyDataDefinedProperties( sl );
00215   return sl;
00216 }
00217 
00218 void QgsSimpleFillSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
00219 {
00220   if ( mBrushStyle == Qt::NoBrush && mBorderStyle == Qt::NoPen )
00221     return;
00222 
00223   QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
00224   if ( !props.value( "uom", "" ).isEmpty() )
00225     symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
00226   element.appendChild( symbolizerElem );
00227 
00228   // <Geometry>
00229   QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
00230 
00231   if ( mBrushStyle != Qt::NoBrush )
00232   {
00233     // <Fill>
00234     QDomElement fillElem = doc.createElement( "se:Fill" );
00235     symbolizerElem.appendChild( fillElem );
00236     QgsSymbolLayerV2Utils::fillToSld( doc, fillElem, mBrushStyle, mColor );
00237   }
00238 
00239   if ( mBorderStyle != Qt::NoPen )
00240   {
00241     // <Stroke>
00242     QDomElement strokeElem = doc.createElement( "se:Stroke" );
00243     symbolizerElem.appendChild( strokeElem );
00244     QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, mBorderStyle, mBorderColor, mBorderWidth );
00245   }
00246 
00247   // <se:Displacement>
00248   QgsSymbolLayerV2Utils::createDisplacementElement( doc, symbolizerElem, mOffset );
00249 }
00250 
00251 QString QgsSimpleFillSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
00252 {
00253   //brush
00254   QString symbolStyle;
00255   symbolStyle.append( QgsSymbolLayerV2Utils::ogrFeatureStyleBrush( mColor ) );
00256   symbolStyle.append( ";" );
00257   //pen
00258   symbolStyle.append( QgsSymbolLayerV2Utils::ogrFeatureStylePen( mBorderWidth, mmScaleFactor, mapUnitScaleFactor, mBorderColor ) );
00259   return symbolStyle;
00260 }
00261 
00262 QgsSymbolLayerV2* QgsSimpleFillSymbolLayerV2::createFromSld( QDomElement &element )
00263 {
00264   QgsDebugMsg( "Entered." );
00265 
00266   QColor color, borderColor;
00267   Qt::BrushStyle fillStyle;
00268   Qt::PenStyle borderStyle;
00269   double borderWidth;
00270 
00271   QDomElement fillElem = element.firstChildElement( "Fill" );
00272   QgsSymbolLayerV2Utils::fillFromSld( fillElem, fillStyle, color );
00273 
00274   QDomElement strokeElem = element.firstChildElement( "Stroke" );
00275   QgsSymbolLayerV2Utils::lineFromSld( strokeElem, borderStyle, borderColor, borderWidth );
00276 
00277   QPointF offset;
00278   QgsSymbolLayerV2Utils::displacementFromSldElement( element, offset );
00279 
00280   QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( color, fillStyle, borderColor, borderStyle, borderWidth );
00281   sl->setOffset( offset );
00282   return sl;
00283 }
00284 
00285 
00286 //QgsImageFillSymbolLayer
00287 
00288 QgsImageFillSymbolLayer::QgsImageFillSymbolLayer(): mOutlineWidth( 0.0 ), mOutlineWidthUnit( QgsSymbolV2::MM ), mOutline( 0 )
00289 {
00290   setSubSymbol( new QgsLineSymbolV2() );
00291 }
00292 
00293 QgsImageFillSymbolLayer::~QgsImageFillSymbolLayer()
00294 {
00295 }
00296 
00297 void QgsImageFillSymbolLayer::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
00298 {
00299   QPainter* p = context.renderContext().painter();
00300   if ( !p )
00301   {
00302     return;
00303   }
00304 
00305   applyDataDefinedSettings( context );
00306 
00307   p->setPen( QPen( Qt::NoPen ) );
00308   if ( context.selected() )
00309   {
00310     QColor selColor = context.renderContext().selectionColor();
00311     // Alister - this doesn't seem to work here
00312     //if ( ! selectionIsOpaque )
00313     //  selColor.setAlphaF( context.alpha() );
00314     p->setBrush( QBrush( selColor ) );
00315     _renderPolygon( p, points, rings );
00316   }
00317 
00318   if ( qgsDoubleNear( mAngle, 0.0 ) )
00319   {
00320     p->setBrush( mBrush );
00321   }
00322   else
00323   {
00324     QTransform t = mBrush.transform();
00325     t.rotate( mAngle );
00326     QBrush rotatedBrush = mBrush;
00327     rotatedBrush.setTransform( t );
00328     p->setBrush( rotatedBrush );
00329   }
00330   _renderPolygon( p, points, rings );
00331   if ( mOutline )
00332   {
00333     mOutline->renderPolyline( points, context.feature(), context.renderContext(), -1, selectFillBorder && context.selected() );
00334     if ( rings )
00335     {
00336       QList<QPolygonF>::const_iterator ringIt = rings->constBegin();
00337       for ( ; ringIt != rings->constEnd(); ++ringIt )
00338       {
00339         mOutline->renderPolyline( *ringIt, context.feature(), context.renderContext(), -1, selectFillBorder && context.selected() );
00340       }
00341     }
00342   }
00343 }
00344 
00345 bool QgsImageFillSymbolLayer::setSubSymbol( QgsSymbolV2* symbol )
00346 {
00347   if ( !symbol ) //unset current outline
00348   {
00349     delete mOutline;
00350     mOutline = 0;
00351     return true;
00352   }
00353 
00354   if ( symbol->type() != QgsSymbolV2::Line )
00355   {
00356     delete symbol;
00357     return false;
00358   }
00359 
00360   QgsLineSymbolV2* lineSymbol = dynamic_cast<QgsLineSymbolV2*>( symbol );
00361   if ( lineSymbol )
00362   {
00363     delete mOutline;
00364     mOutline = lineSymbol;
00365     return true;
00366   }
00367 
00368   delete symbol;
00369   return false;
00370 }
00371 
00372 //QgsSVGFillSymbolLayer
00373 
00374 QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QString& svgFilePath, double width, double angle ): QgsImageFillSymbolLayer(), mPatternWidth( width ),
00375     mPatternWidthUnit( QgsSymbolV2::MM ), mSvgOutlineWidthUnit( QgsSymbolV2::MM )
00376 {
00377   setSvgFilePath( svgFilePath );
00378   mOutlineWidth = 0.3;
00379   mAngle = angle;
00380   setDefaultSvgParams();
00381   mSvgPattern = 0;
00382 }
00383 
00384 QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QByteArray& svgData, double width, double angle ): QgsImageFillSymbolLayer(), mPatternWidth( width ),
00385     mSvgData( svgData )
00386 {
00387   storeViewBox();
00388   mOutlineWidth = 0.3;
00389   mAngle = angle;
00390   setSubSymbol( new QgsLineSymbolV2() );
00391   setDefaultSvgParams();
00392   mSvgPattern = 0;
00393 }
00394 
00395 QgsSVGFillSymbolLayer::~QgsSVGFillSymbolLayer()
00396 {
00397   delete mOutline;
00398   delete mSvgPattern;
00399 }
00400 
00401 void QgsSVGFillSymbolLayer::setOutputUnit( QgsSymbolV2::OutputUnit unit )
00402 {
00403   mPatternWidthUnit = unit;
00404   mSvgOutlineWidthUnit = unit;
00405   mOutlineWidthUnit = unit;
00406 }
00407 
00408 QgsSymbolV2::OutputUnit QgsSVGFillSymbolLayer::outputUnit() const
00409 {
00410   QgsSymbolV2::OutputUnit unit = mPatternWidthUnit;
00411   if ( mSvgOutlineWidthUnit != unit || mOutlineWidthUnit != unit )
00412   {
00413     return QgsSymbolV2::Mixed;
00414   }
00415   return unit;
00416 }
00417 
00418 void QgsSVGFillSymbolLayer::setSvgFilePath( const QString& svgPath )
00419 {
00420   mSvgData = QgsSvgCache::instance()->getImageData( svgPath );
00421   storeViewBox();
00422 
00423   mSvgFilePath = svgPath;
00424   setDefaultSvgParams();
00425 }
00426 
00427 QgsSymbolLayerV2* QgsSVGFillSymbolLayer::create( const QgsStringMap& properties )
00428 {
00429   QByteArray data;
00430   double width = 20;
00431   QString svgFilePath;
00432   double angle = 0.0;
00433 
00434   if ( properties.contains( "width" ) )
00435   {
00436     width = properties["width"].toDouble();
00437   }
00438   if ( properties.contains( "svgFile" ) )
00439   {
00440     QString svgName = properties["svgFile"];
00441     QString savePath = QgsSymbolLayerV2Utils::symbolNameToPath( svgName );
00442     svgFilePath = ( savePath.isEmpty() ? svgName : savePath );
00443   }
00444   if ( properties.contains( "angle" ) )
00445   {
00446     angle = properties["angle"].toDouble();
00447   }
00448 
00449   QgsSVGFillSymbolLayer* symbolLayer = 0;
00450   if ( !svgFilePath.isEmpty() )
00451   {
00452     symbolLayer = new QgsSVGFillSymbolLayer( svgFilePath, width, angle );
00453   }
00454   else
00455   {
00456     if ( properties.contains( "data" ) )
00457     {
00458       data = QByteArray::fromHex( properties["data"].toLocal8Bit() );
00459     }
00460     symbolLayer = new QgsSVGFillSymbolLayer( data, width, angle );
00461   }
00462 
00463   //svg parameters
00464   if ( properties.contains( "svgFillColor" ) )
00465   {
00466     symbolLayer->setSvgFillColor( QColor( properties["svgFillColor"] ) );
00467   }
00468   if ( properties.contains( "svgOutlineColor" ) )
00469   {
00470     symbolLayer->setSvgOutlineColor( QColor( properties["svgOutlineColor"] ) );
00471   }
00472   if ( properties.contains( "svgOutlineWidth" ) )
00473   {
00474     symbolLayer->setSvgOutlineWidth( properties["svgOutlineWidth"].toDouble() );
00475   }
00476 
00477   //units
00478   if ( properties.contains( "pattern_width_unit" ) )
00479   {
00480     symbolLayer->setPatternWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["pattern_width_unit"] ) );
00481   }
00482   if ( properties.contains( "svg_outline_width_unit" ) )
00483   {
00484     symbolLayer->setSvgOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["svg_outline_width_unit"] ) );
00485   }
00486   if ( properties.contains( "outline_width_unit" ) )
00487   {
00488     symbolLayer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
00489   }
00490 
00491   if ( properties.contains( "width_expression" ) )
00492     symbolLayer->setDataDefinedProperty( "width", properties["width_expression"] );
00493   if ( properties.contains( "svgFile_expression" ) )
00494     symbolLayer->setDataDefinedProperty( "svgFile", properties["svgFile_expression"] );
00495   if ( properties.contains( "angle_expression" ) )
00496     symbolLayer->setDataDefinedProperty( "angle", properties["angle_expression"] );
00497   if ( properties.contains( "svgFillColor_expression" ) )
00498     symbolLayer->setDataDefinedProperty( "svgFillColor", "svgFillColor_expression" );
00499   if ( properties.contains( "svgOutlineColor_expression" ) )
00500     symbolLayer->setDataDefinedProperty( "svgOutlineColor", "svgOutlineColor_expression" );
00501   if ( properties.contains( "svgOutlineWidth" ) )
00502     symbolLayer->setDataDefinedProperty( "svgOutlineWidth", "svgOutlineWidth_expression" );
00503 
00504   return symbolLayer;
00505 }
00506 
00507 QString QgsSVGFillSymbolLayer::layerType() const
00508 {
00509   return "SVGFill";
00510 }
00511 
00512 void QgsSVGFillSymbolLayer::applyPattern( QBrush& brush, const QString& svgFilePath, double patternWidth, QgsSymbolV2::OutputUnit patternWidthUnit,
00513     const QColor& svgFillColor, const QColor& svgOutlineColor, double svgOutlineWidth,
00514     QgsSymbolV2::OutputUnit svgOutlineWidthUnit, const QgsSymbolV2RenderContext& context )
00515 {
00516   if ( mSvgViewBox.isNull() )
00517   {
00518     return;
00519   }
00520 
00521   delete mSvgPattern;
00522   mSvgPattern = 0;
00523   double size = patternWidth * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( context.renderContext(), patternWidthUnit );
00524 
00525   if (( int )size < 1.0 || 10000.0 < size )
00526   {
00527     mSvgPattern = new QImage();
00528     brush.setTextureImage( *mSvgPattern );
00529   }
00530   else
00531   {
00532     bool fitsInCache = true;
00533     double outlineWidth = svgOutlineWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), svgOutlineWidthUnit );
00534     const QImage& patternImage = QgsSvgCache::instance()->svgAsImage( svgFilePath, size, svgFillColor, svgOutlineColor, outlineWidth,
00535                                  context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
00536     if ( !fitsInCache )
00537     {
00538       const QPicture& patternPict = QgsSvgCache::instance()->svgAsPicture( svgFilePath, size, svgFillColor, svgOutlineColor, outlineWidth,
00539                                     context.renderContext().scaleFactor(), 1.0 );
00540       double hwRatio = 1.0;
00541       if ( patternPict.width() > 0 )
00542       {
00543         hwRatio = ( double )patternPict.height() / ( double )patternPict.width();
00544       }
00545       mSvgPattern = new QImage(( int )size, ( int )( size * hwRatio ), QImage::Format_ARGB32_Premultiplied );
00546       mSvgPattern->fill( 0 ); // transparent background
00547 
00548       QPainter p( mSvgPattern );
00549       p.drawPicture( QPointF( size / 2, size * hwRatio / 2 ), patternPict );
00550     }
00551 
00552     QTransform brushTransform;
00553     brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
00554     if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
00555     {
00556       QImage transparentImage = fitsInCache ? patternImage.copy() : mSvgPattern->copy();
00557       QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
00558       brush.setTextureImage( transparentImage );
00559     }
00560     else
00561     {
00562       brush.setTextureImage( fitsInCache ? patternImage : *mSvgPattern );
00563     }
00564     brush.setTransform( brushTransform );
00565   }
00566 }
00567 
00568 void QgsSVGFillSymbolLayer::startRender( QgsSymbolV2RenderContext& context )
00569 {
00570 
00571   applyPattern( mBrush, mSvgFilePath, mPatternWidth, mPatternWidthUnit, mSvgFillColor, mSvgOutlineColor, mSvgOutlineWidth, mSvgOutlineWidthUnit, context );
00572 
00573   if ( mOutline )
00574   {
00575     mOutline->startRender( context.renderContext() );
00576   }
00577 
00578   prepareExpressions( context.layer() );
00579 }
00580 
00581 void QgsSVGFillSymbolLayer::stopRender( QgsSymbolV2RenderContext& context )
00582 {
00583   if ( mOutline )
00584   {
00585     mOutline->stopRender( context.renderContext() );
00586   }
00587 }
00588 
00589 QgsStringMap QgsSVGFillSymbolLayer::properties() const
00590 {
00591   QgsStringMap map;
00592   if ( !mSvgFilePath.isEmpty() )
00593   {
00594     map.insert( "svgFile", QgsSymbolLayerV2Utils::symbolPathToName( mSvgFilePath ) );
00595   }
00596   else
00597   {
00598     map.insert( "data", QString( mSvgData.toHex() ) );
00599   }
00600 
00601   map.insert( "width", QString::number( mPatternWidth ) );
00602   map.insert( "angle", QString::number( mAngle ) );
00603 
00604   //svg parameters
00605   map.insert( "svgFillColor", mSvgFillColor.name() );
00606   map.insert( "svgOutlineColor", mSvgOutlineColor.name() );
00607   map.insert( "svgOutlineWidth", QString::number( mSvgOutlineWidth ) );
00608 
00609   //units
00610   map["pattern_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mPatternWidthUnit );
00611   map["svg_outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSvgOutlineWidthUnit );
00612   map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
00613 
00614   saveDataDefinedProperties( map );
00615   return map;
00616 }
00617 
00618 QgsSymbolLayerV2* QgsSVGFillSymbolLayer::clone() const
00619 {
00620   QgsSVGFillSymbolLayer* clonedLayer = 0;
00621   if ( !mSvgFilePath.isEmpty() )
00622   {
00623     clonedLayer = new QgsSVGFillSymbolLayer( mSvgFilePath, mPatternWidth, mAngle );
00624     clonedLayer->setSvgFillColor( mSvgFillColor );
00625     clonedLayer->setSvgOutlineColor( mSvgOutlineColor );
00626     clonedLayer->setSvgOutlineWidth( mSvgOutlineWidth );
00627   }
00628   else
00629   {
00630     clonedLayer = new QgsSVGFillSymbolLayer( mSvgData, mPatternWidth, mAngle );
00631   }
00632 
00633   clonedLayer->setPatternWidthUnit( mPatternWidthUnit );
00634   clonedLayer->setSvgOutlineWidthUnit( mSvgOutlineWidthUnit );
00635   clonedLayer->setOutlineWidthUnit( mOutlineWidthUnit );
00636 
00637   if ( mOutline )
00638   {
00639     clonedLayer->setSubSymbol( mOutline->clone() );
00640   }
00641   copyDataDefinedProperties( clonedLayer );
00642   return clonedLayer;
00643 }
00644 
00645 void QgsSVGFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
00646 {
00647   QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
00648   if ( !props.value( "uom", "" ).isEmpty() )
00649     symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
00650   element.appendChild( symbolizerElem );
00651 
00652   QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
00653 
00654   QDomElement fillElem = doc.createElement( "se:Fill" );
00655   symbolizerElem.appendChild( fillElem );
00656 
00657   QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
00658   fillElem.appendChild( graphicFillElem );
00659 
00660   QDomElement graphicElem = doc.createElement( "se:Graphic" );
00661   graphicFillElem.appendChild( graphicElem );
00662 
00663   if ( !mSvgFilePath.isEmpty() )
00664   {
00665     QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mSvgFilePath, "image/svg+xml", mSvgFillColor, mPatternWidth );
00666   }
00667   else
00668   {
00669     // TODO: create svg from data
00670     // <se:InlineContent>
00671     symbolizerElem.appendChild( doc.createComment( "SVG from data not implemented yet" ) );
00672   }
00673 
00674   if ( mSvgOutlineColor.isValid() || mSvgOutlineWidth >= 0 )
00675   {
00676     QgsSymbolLayerV2Utils::lineToSld( doc, graphicElem, Qt::SolidLine, mSvgOutlineColor, mSvgOutlineWidth );
00677   }
00678 
00679   // <Rotation>
00680   QString angleFunc;
00681   bool ok;
00682   double angle = props.value( "angle", "0" ).toDouble( &ok );
00683   if ( !ok )
00684   {
00685     angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
00686   }
00687   else if ( angle + mAngle != 0 )
00688   {
00689     angleFunc = QString::number( angle + mAngle );
00690   }
00691   QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
00692 
00693   if ( mOutline )
00694   {
00695     // the outline sub symbol should be stored within the Stroke element,
00696     // but it will be stored in a separated LineSymbolizer because it could
00697     // have more than one layer
00698     mOutline->toSld( doc, element, props );
00699   }
00700 }
00701 
00702 QgsSymbolLayerV2* QgsSVGFillSymbolLayer::createFromSld( QDomElement &element )
00703 {
00704   QgsDebugMsg( "Entered." );
00705 
00706   QString path, mimeType;
00707   QColor fillColor, borderColor;
00708   Qt::PenStyle penStyle;
00709   double size, borderWidth;
00710 
00711   QDomElement fillElem = element.firstChildElement( "Fill" );
00712   if ( fillElem.isNull() )
00713     return NULL;
00714 
00715   QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
00716   if ( graphicFillElem.isNull() )
00717     return NULL;
00718 
00719   QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
00720   if ( graphicElem.isNull() )
00721     return NULL;
00722 
00723   if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
00724     return NULL;
00725 
00726   if ( mimeType != "image/svg+xml" )
00727     return NULL;
00728 
00729   QgsSymbolLayerV2Utils::lineFromSld( graphicElem, penStyle, borderColor, borderWidth );
00730 
00731   double angle = 0.0;
00732   QString angleFunc;
00733   if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
00734   {
00735     bool ok;
00736     double d = angleFunc.toDouble( &ok );
00737     if ( ok )
00738       angle = d;
00739   }
00740 
00741   QgsSVGFillSymbolLayer* sl = new QgsSVGFillSymbolLayer( path, size, angle );
00742   sl->setSvgFillColor( fillColor );
00743   sl->setSvgOutlineColor( borderColor );
00744   sl->setSvgOutlineWidth( borderWidth );
00745 
00746   // try to get the outline
00747   QDomElement strokeElem = element.firstChildElement( "Stroke" );
00748   if ( !strokeElem.isNull() )
00749   {
00750     QgsSymbolLayerV2 *l = QgsSymbolLayerV2Utils::createLineLayerFromSld( strokeElem );
00751     if ( l )
00752     {
00753       QgsSymbolLayerV2List layers;
00754       layers.append( l );
00755       sl->setSubSymbol( new QgsLineSymbolV2( layers ) );
00756     }
00757   }
00758 
00759   return sl;
00760 }
00761 
00762 void QgsSVGFillSymbolLayer::applyDataDefinedSettings( const QgsSymbolV2RenderContext& context )
00763 {
00764   QgsExpression* widthExpression = expression( "width" );
00765   QgsExpression* svgFileExpression = expression( "svgFile" );
00766   QgsExpression* fillColorExpression = expression( "svgFillColor" );
00767   QgsExpression* outlineColorExpression = expression( "svgOutlineColor" );
00768   QgsExpression* outlineWidthExpression = expression( "svgOutlineWidth" );
00769   if ( !widthExpression && !svgFileExpression && !fillColorExpression && !outlineColorExpression && !outlineWidthExpression )
00770   {
00771     return; //no data defined settings
00772   }
00773 
00774   double width = mPatternWidth;
00775   if ( widthExpression )
00776   {
00777     width = widthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
00778   }
00779   QString svgFile = mSvgFilePath;
00780   if ( svgFileExpression )
00781   {
00782     svgFile = svgFileExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
00783   }
00784   QColor svgFillColor = mSvgFillColor;
00785   if ( fillColorExpression )
00786   {
00787     svgFillColor = QgsSymbolLayerV2Utils::decodeColor( fillColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
00788   }
00789   QColor svgOutlineColor = mSvgOutlineColor;
00790   if ( outlineColorExpression )
00791   {
00792     svgOutlineColor = QgsSymbolLayerV2Utils::decodeColor( outlineColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
00793   }
00794   double outlineWidth = mSvgOutlineWidth;
00795   if ( outlineWidthExpression )
00796   {
00797     outlineWidth = outlineWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
00798   }
00799   applyPattern( mBrush, svgFile, width, mPatternWidthUnit, svgFillColor, svgOutlineColor, outlineWidth,
00800                 mSvgOutlineWidthUnit, context );
00801 
00802 }
00803 
00804 void QgsSVGFillSymbolLayer::storeViewBox()
00805 {
00806   if ( !mSvgData.isEmpty() )
00807   {
00808     QSvgRenderer r( mSvgData );
00809     if ( r.isValid() )
00810     {
00811       mSvgViewBox = r.viewBoxF();
00812       return;
00813     }
00814   }
00815 
00816   mSvgViewBox = QRectF();
00817   return;
00818 }
00819 
00820 void QgsSVGFillSymbolLayer::setDefaultSvgParams()
00821 {
00822   //default values
00823   mSvgFillColor = QColor( 0, 0, 0 );
00824   mSvgOutlineColor = QColor( 0, 0, 0 );
00825   mSvgOutlineWidth = 0.3;
00826 
00827   if ( mSvgFilePath.isEmpty() )
00828   {
00829     return;
00830   }
00831 
00832   bool hasFillParam, hasOutlineParam, hasOutlineWidthParam;
00833   QColor defaultFillColor, defaultOutlineColor;
00834   double defaultOutlineWidth;
00835   QgsSvgCache::instance()->containsParams( mSvgFilePath, hasFillParam, defaultFillColor, hasOutlineParam, defaultOutlineColor, hasOutlineWidthParam,
00836       defaultOutlineWidth );
00837 
00838   if ( hasFillParam )
00839   {
00840     mSvgFillColor = defaultFillColor;
00841   }
00842   if ( hasOutlineParam )
00843   {
00844     mSvgOutlineColor = defaultOutlineColor;
00845   }
00846   if ( hasOutlineWidthParam )
00847   {
00848     mSvgOutlineWidth = defaultOutlineWidth;
00849   }
00850 }
00851 
00852 QgsLinePatternFillSymbolLayer::QgsLinePatternFillSymbolLayer(): QgsImageFillSymbolLayer(), mDistanceUnit( QgsSymbolV2::MM ), mLineWidthUnit( QgsSymbolV2::MM ),
00853     mOffsetUnit( QgsSymbolV2::MM )
00854 {
00855 }
00856 
00857 QgsLinePatternFillSymbolLayer::~QgsLinePatternFillSymbolLayer()
00858 {
00859 }
00860 
00861 void QgsLinePatternFillSymbolLayer::setOutputUnit( QgsSymbolV2::OutputUnit unit )
00862 {
00863   mDistanceUnit = unit;
00864   mLineWidthUnit = unit;
00865   mOffsetUnit = unit;
00866 }
00867 
00868 QgsSymbolV2::OutputUnit QgsLinePatternFillSymbolLayer::outputUnit() const
00869 {
00870   QgsSymbolV2::OutputUnit unit = mDistanceUnit;
00871   if ( mLineWidthUnit != unit || mOffsetUnit != unit )
00872   {
00873     return QgsSymbolV2::Mixed;
00874   }
00875   return unit;
00876 }
00877 
00878 QgsSymbolLayerV2* QgsLinePatternFillSymbolLayer::create( const QgsStringMap& properties )
00879 {
00880   QgsLinePatternFillSymbolLayer* patternLayer = new QgsLinePatternFillSymbolLayer();
00881 
00882   //default values
00883   double lineAngle = 45;
00884   double distance = 5;
00885   double lineWidth = 0.5;
00886   QColor color( Qt::black );
00887   double offset = 0.0;
00888 
00889   if ( properties.contains( "lineangle" ) )
00890   {
00891     lineAngle = properties["lineangle"].toDouble();
00892   }
00893   patternLayer->setLineAngle( lineAngle );
00894 
00895   if ( properties.contains( "distance" ) )
00896   {
00897     distance = properties["distance"].toDouble();
00898   }
00899   patternLayer->setDistance( distance );
00900 
00901   if ( properties.contains( "linewidth" ) )
00902   {
00903     lineWidth = properties["linewidth"].toDouble();
00904   }
00905   patternLayer->setLineWidth( lineWidth );
00906 
00907   if ( properties.contains( "color" ) )
00908   {
00909     color = QgsSymbolLayerV2Utils::decodeColor( properties["color"] );
00910   }
00911   patternLayer->setColor( color );
00912 
00913   if ( properties.contains( "offset" ) )
00914   {
00915     offset = properties["offset"].toDouble();
00916   }
00917   patternLayer->setOffset( offset );
00918 
00919 
00920   if ( properties.contains( "distance_unit" ) )
00921   {
00922     patternLayer->setDistanceUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_unit"] ) );
00923   }
00924   if ( properties.contains( "line_width_unit" ) )
00925   {
00926     patternLayer->setLineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["line_width_unit"] ) );
00927   }
00928   if ( properties.contains( "offset_unit" ) )
00929   {
00930     patternLayer->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["offset_unit"] ) );
00931   }
00932 
00933   //data defined properties
00934   if ( properties.contains( "lineangle_expression" ) )
00935   {
00936     patternLayer->setDataDefinedProperty( "lineangle", properties["lineangle_expression"] );
00937   }
00938   if ( properties.contains( "distance_expression" ) )
00939   {
00940     patternLayer->setDataDefinedProperty( "distance", properties["distance_expression"] );
00941   }
00942   if ( properties.contains( "linewidth_expression" ) )
00943   {
00944     patternLayer->setDataDefinedProperty( "linewidth", properties["linewidth_expression"] );
00945   }
00946   if ( properties.contains( "color_expression" ) )
00947   {
00948     patternLayer->setDataDefinedProperty( "color", properties["color_expression"] );
00949   }
00950   return patternLayer;
00951 }
00952 
00953 QString QgsLinePatternFillSymbolLayer::layerType() const
00954 {
00955   return "LinePatternFill";
00956 }
00957 
00958 void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext& context, QBrush& brush, double lineAngle, double distance,
00959     double lineWidth, const QColor& color )
00960 {
00961   const QgsRenderContext& ctx = context.renderContext();
00962   double outlinePixelWidth = lineWidth * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx,  mLineWidthUnit );
00963   double outputPixelDist = distance * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDistanceUnit );
00964   double outputPixelOffset = mOffset * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx,  mOffsetUnit );
00965 
00966   //create image
00967   int height, width;
00968   if ( qgsDoubleNear( lineAngle, 0 ) || qgsDoubleNear( lineAngle, 360 ) || qgsDoubleNear( lineAngle, 90 ) || qgsDoubleNear( lineAngle, 180 ) || qgsDoubleNear( lineAngle, 270 ) )
00969   {
00970     height = outputPixelDist;
00971     width = height; //width can be set to arbitrary value
00972   }
00973   else
00974   {
00975     height = qAbs( outputPixelDist / cos( lineAngle * M_PI / 180 ) ); //keep perpendicular distance between lines constant
00976     width = qAbs( height / tan( lineAngle * M_PI / 180 ) );
00977   }
00978 
00979   //depending on the angle, we might need to render into a larger image and use a subset of it
00980   int dx = 0;
00981   int dy = 0;
00982 
00983   if ( width > 10000 || height > 10000 ) //protect symbol layer from eating too much memory
00984   {
00985     QImage img;
00986     mBrush.setTextureImage( img );
00987     return;
00988   }
00989 
00990   QImage patternImage( width, height, QImage::Format_ARGB32 );
00991   patternImage.fill( 0 );
00992   QPainter p( &patternImage );
00993 
00994   p.setRenderHint( QPainter::Antialiasing, true );
00995   QPen pen( color );
00996   pen.setWidthF( outlinePixelWidth );
00997   pen.setCapStyle( Qt::FlatCap );
00998   p.setPen( pen );
00999 
01000   QPoint p1, p2, p3, p4, p5, p6;
01001   if ( qgsDoubleNear( lineAngle, 0.0 ) || qgsDoubleNear( lineAngle, 360.0 ) || qgsDoubleNear( lineAngle, 180.0 ) )
01002   {
01003     p1 = QPoint( 0, height );
01004     p2 = QPoint( width, height );
01005     p3 = QPoint( 0, 0 );
01006     p4 = QPoint( width, 0 );
01007     p5 = QPoint( 0, 2 * height );
01008     p6 = QPoint( width, 2 * height );
01009   }
01010   else if ( qgsDoubleNear( lineAngle, 90.0 ) || qgsDoubleNear( lineAngle, 270.0 ) )
01011   {
01012     p1 = QPoint( 0, height );
01013     p2 = QPoint( 0, 0 );
01014     p3 = QPoint( width, height );
01015     p4 = QPoint( width, 0 );
01016     p5 = QPoint( -width, height );
01017     p6 = QPoint( -width, 0 );
01018   }
01019   else if (( lineAngle > 0 && lineAngle < 90 ) || ( lineAngle > 180 && lineAngle < 270 ) )
01020   {
01021     dx = outputPixelDist * cos(( 90 - lineAngle ) * M_PI / 180.0 );
01022     dy = outputPixelDist * sin(( 90 - lineAngle ) * M_PI / 180.0 );
01023     p1 = QPoint( 0, height );
01024     p2 = QPoint( width, 0 );
01025     p3 = QPoint( -dx, height - dy );
01026     p4 = QPoint( width - dx, -dy ); //p4 = QPoint( p3.x() + width, p3.y() - height );
01027     p5 = QPoint( dx, height + dy );
01028     p6 = QPoint( width + dx, dy ); //p6 = QPoint( p5.x() + width, p5.y() - height );
01029   }
01030   else if (( lineAngle < 180 ) || ( lineAngle > 270 && lineAngle < 360 ) )
01031   {
01032     dy = outputPixelDist * cos(( 180 - lineAngle ) * M_PI / 180 );
01033     dx = outputPixelDist * sin(( 180 - lineAngle ) * M_PI / 180 );
01034     p1 = QPoint( width, height );
01035     p2 = QPoint( 0, 0 );
01036     p5 = QPoint( width + dx, height - dy );
01037     p6 = QPoint( p5.x() - width, p5.y() - height ); //p6 = QPoint( dx, -dy );
01038     p3 = QPoint( width - dx, height + dy );
01039     p4 = QPoint( p3.x() - width, p3.y() - height ); //p4 = QPoint( -dx, dy );
01040   }
01041 
01042   if ( !qgsDoubleNear( mOffset, 0.0 ) ) //shift everything
01043   {
01044     QPointF tempPt;
01045     tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p3, outputPixelDist + outputPixelOffset );
01046     p3 = QPoint( tempPt.x(), tempPt.y() );
01047     tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p4, outputPixelDist + outputPixelOffset );
01048     p4 = QPoint( tempPt.x(), tempPt.y() );
01049     tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p5, outputPixelDist - outputPixelOffset );
01050     p5 = QPoint( tempPt.x(), tempPt.y() );
01051     tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p6, outputPixelDist - outputPixelOffset );
01052     p6 = QPoint( tempPt.x(), tempPt.y() );
01053 
01054     //update p1, p2 last
01055     tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p3, outputPixelOffset ).toPoint();
01056     p1 = QPoint( tempPt.x(), tempPt.y() );
01057     tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p4, outputPixelOffset ).toPoint();
01058     p2 = QPoint( tempPt.x(), tempPt.y() );;
01059   }
01060 
01061   p.drawLine( p1, p2 );
01062   p.drawLine( p3, p4 );
01063   p.drawLine( p5, p6 );
01064   p.end();
01065 
01066   //set image to mBrush
01067   if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
01068   {
01069     QImage transparentImage = patternImage.copy();
01070     QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
01071     brush.setTextureImage( transparentImage );
01072   }
01073   else
01074   {
01075     brush.setTextureImage( patternImage );
01076   }
01077 
01078   QTransform brushTransform;
01079   brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
01080   brush.setTransform( brushTransform );
01081 }
01082 
01083 void QgsLinePatternFillSymbolLayer::startRender( QgsSymbolV2RenderContext& context )
01084 {
01085   applyPattern( context, mBrush, mLineAngle, mDistance, mLineWidth, mColor );
01086 
01087   if ( mOutline )
01088   {
01089     mOutline->startRender( context.renderContext() );
01090   }
01091 
01092   prepareExpressions( context.layer() );
01093 }
01094 
01095 void QgsLinePatternFillSymbolLayer::stopRender( QgsSymbolV2RenderContext & )
01096 {
01097 }
01098 
01099 QgsStringMap QgsLinePatternFillSymbolLayer::properties() const
01100 {
01101   QgsStringMap map;
01102   map.insert( "lineangle", QString::number( mLineAngle ) );
01103   map.insert( "distance", QString::number( mDistance ) );
01104   map.insert( "linewidth", QString::number( mLineWidth ) );
01105   map.insert( "color", QgsSymbolLayerV2Utils::encodeColor( mColor ) );
01106   map.insert( "offset", QString::number( mOffset ) );
01107   map.insert( "distance_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceUnit ) );
01108   map.insert( "line_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mLineWidthUnit ) );
01109   map.insert( "offset_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit ) );
01110   saveDataDefinedProperties( map );
01111   return map;
01112 }
01113 
01114 QgsSymbolLayerV2* QgsLinePatternFillSymbolLayer::clone() const
01115 {
01116   QgsLinePatternFillSymbolLayer* clonedLayer = static_cast<QgsLinePatternFillSymbolLayer*>( QgsLinePatternFillSymbolLayer::create( properties() ) );
01117   if ( mOutline )
01118   {
01119     clonedLayer->setSubSymbol( mOutline->clone() );
01120   }
01121   clonedLayer->setDistanceUnit( mDistanceUnit );
01122   clonedLayer->setLineWidthUnit( mLineWidthUnit );
01123   clonedLayer->setOffsetUnit( mOffsetUnit );
01124   copyDataDefinedProperties( clonedLayer );
01125   return clonedLayer;
01126 }
01127 
01128 void QgsLinePatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
01129 {
01130   QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
01131   if ( !props.value( "uom", "" ).isEmpty() )
01132     symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
01133   element.appendChild( symbolizerElem );
01134 
01135   // <Geometry>
01136   QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
01137 
01138   QDomElement fillElem = doc.createElement( "se:Fill" );
01139   symbolizerElem.appendChild( fillElem );
01140 
01141   QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
01142   fillElem.appendChild( graphicFillElem );
01143 
01144   QDomElement graphicElem = doc.createElement( "se:Graphic" );
01145   graphicFillElem.appendChild( graphicElem );
01146 
01147   QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, "horline", QColor(), mColor, mLineWidth, mDistance );
01148 
01149   // <Rotation>
01150   QString angleFunc;
01151   bool ok;
01152   double angle = props.value( "angle", "0" ).toDouble( &ok );
01153   if ( !ok )
01154   {
01155     angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mLineAngle );
01156   }
01157   else if ( angle + mLineAngle != 0 )
01158   {
01159     angleFunc = QString::number( angle + mLineAngle );
01160   }
01161   QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
01162 
01163   // <se:Displacement>
01164   QPointF lineOffset( sin( mLineAngle ) * mOffset, cos( mLineAngle ) * mOffset );
01165   QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, lineOffset );
01166 
01167   if ( mOutline )
01168   {
01169     // the outline sub symbol should be stored within the Stroke element,
01170     // but it will be stored in a separated LineSymbolizer because it could
01171     // have more than one layer
01172     mOutline->toSld( doc, element, props );
01173   }
01174 }
01175 
01176 QString QgsLinePatternFillSymbolLayer::ogrFeatureStyleWidth( double widthScaleFactor ) const
01177 {
01178   QString featureStyle;
01179   featureStyle.append( "Brush(" );
01180   featureStyle.append( QString( "fc:%1" ).arg( mColor.name() ) );
01181   featureStyle.append( QString( ",bc:%1" ).arg( "#00000000" ) ); //transparent background
01182   featureStyle.append( ",id:\"ogr-brush-2\"" );
01183   featureStyle.append( QString( ",a:%1" ).arg( mLineAngle ) );
01184   featureStyle.append( QString( ",s:%1" ).arg( mLineWidth * widthScaleFactor ) );
01185   featureStyle.append( ",dx:0mm" );
01186   featureStyle.append( QString( ",dy:%1mm" ).arg( mDistance * widthScaleFactor ) );
01187   featureStyle.append( ")" );
01188   return featureStyle;
01189 }
01190 
01191 void QgsLinePatternFillSymbolLayer::applyDataDefinedSettings( const QgsSymbolV2RenderContext& context )
01192 {
01193   QgsExpression* lineAngleExpression = expression( "lineangle" );
01194   QgsExpression* distanceExpression = expression( "distance" );
01195   QgsExpression* lineWidthExpression = expression( "linewidth" );
01196   QgsExpression* colorExpression = expression( "color" );
01197   if ( !lineAngleExpression && !distanceExpression && !lineWidthExpression && !colorExpression )
01198   {
01199     return; //no data defined settings
01200   }
01201 
01202   double lineAngle = mLineAngle;
01203   if ( lineAngleExpression )
01204   {
01205     lineAngle = lineAngleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
01206   }
01207   double distance = mDistance;
01208   if ( distanceExpression )
01209   {
01210     distance = distanceExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
01211   }
01212   double lineWidth = mLineWidth;
01213   if ( lineWidthExpression )
01214   {
01215     lineWidth = lineWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
01216   }
01217   QColor color = mColor;
01218   if ( colorExpression )
01219   {
01220     color = QgsSymbolLayerV2Utils::decodeColor( colorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
01221   }
01222   applyPattern( context, mBrush, lineAngle, distance, lineWidth, color );
01223 }
01224 
01225 QgsSymbolLayerV2* QgsLinePatternFillSymbolLayer::createFromSld( QDomElement &element )
01226 {
01227   QgsDebugMsg( "Entered." );
01228 
01229   QString name;
01230   QColor fillColor, lineColor;
01231   double size, lineWidth;
01232 
01233   QDomElement fillElem = element.firstChildElement( "Fill" );
01234   if ( fillElem.isNull() )
01235     return NULL;
01236 
01237   QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
01238   if ( graphicFillElem.isNull() )
01239     return NULL;
01240 
01241   QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
01242   if ( graphicElem.isNull() )
01243     return NULL;
01244 
01245   if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, fillColor, lineColor, lineWidth, size ) )
01246     return NULL;
01247 
01248   if ( name != "horline" )
01249     return NULL;
01250 
01251   double angle = 0.0;
01252   QString angleFunc;
01253   if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
01254   {
01255     bool ok;
01256     double d = angleFunc.toDouble( &ok );
01257     if ( ok )
01258       angle = d;
01259   }
01260 
01261   double offset = 0.0;
01262   QPointF vectOffset;
01263   if ( QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, vectOffset ) )
01264   {
01265     offset = sqrt( pow( vectOffset.x(), 2 ) + pow( vectOffset.y(), 2 ) );
01266   }
01267 
01268   QgsLinePatternFillSymbolLayer* sl = new QgsLinePatternFillSymbolLayer();
01269   sl->setColor( lineColor );
01270   sl->setLineWidth( lineWidth );
01271   sl->setLineAngle( angle );
01272   sl->setOffset( offset );
01273   sl->setDistance( size );
01274 
01275   // try to get the outline
01276   QDomElement strokeElem = element.firstChildElement( "Stroke" );
01277   if ( !strokeElem.isNull() )
01278   {
01279     QgsSymbolLayerV2 *l = QgsSymbolLayerV2Utils::createLineLayerFromSld( strokeElem );
01280     if ( l )
01281     {
01282       QgsSymbolLayerV2List layers;
01283       layers.append( l );
01284       sl->setSubSymbol( new QgsLineSymbolV2( layers ) );
01285     }
01286   }
01287 
01288   return sl;
01289 }
01290 
01292 
01293 QgsPointPatternFillSymbolLayer::QgsPointPatternFillSymbolLayer(): QgsImageFillSymbolLayer(), mMarkerSymbol( 0 ), mDistanceX( 15 ),
01294     mDistanceXUnit( QgsSymbolV2::MM ), mDistanceY( 15 ), mDistanceYUnit( QgsSymbolV2::MM ), mDisplacementX( 0 ), mDisplacementXUnit( QgsSymbolV2::MM ),
01295     mDisplacementY( 0 ), mDisplacementYUnit( QgsSymbolV2::MM )
01296 {
01297   mDistanceX = 15;
01298   mDistanceY = 15;
01299   mDisplacementX = 0;
01300   mDisplacementY = 0;
01301   setSubSymbol( new QgsMarkerSymbolV2() );
01302   QgsImageFillSymbolLayer::setSubSymbol( 0 ); //no outline
01303 }
01304 
01305 QgsPointPatternFillSymbolLayer::~QgsPointPatternFillSymbolLayer()
01306 {
01307 }
01308 
01309 void QgsPointPatternFillSymbolLayer::setOutputUnit( QgsSymbolV2::OutputUnit unit )
01310 {
01311   mDistanceXUnit = unit;
01312   mDistanceYUnit = unit;
01313   mDisplacementXUnit = unit;
01314   mDisplacementYUnit = unit;
01315 }
01316 
01317 QgsSymbolV2::OutputUnit QgsPointPatternFillSymbolLayer::outputUnit() const
01318 {
01319   QgsSymbolV2::OutputUnit unit = mDistanceXUnit;
01320   if ( mDistanceYUnit != unit || mDisplacementXUnit != unit || mDisplacementYUnit != unit )
01321   {
01322     return QgsSymbolV2::Mixed;
01323   }
01324   return unit;
01325 }
01326 
01327 QgsSymbolLayerV2* QgsPointPatternFillSymbolLayer::create( const QgsStringMap& properties )
01328 {
01329   QgsPointPatternFillSymbolLayer* layer = new QgsPointPatternFillSymbolLayer();
01330   if ( properties.contains( "distance_x" ) )
01331   {
01332     layer->setDistanceX( properties["distance_x"].toDouble() );
01333   }
01334   if ( properties.contains( "distance_y" ) )
01335   {
01336     layer->setDistanceY( properties["distance_y"].toDouble() );
01337   }
01338   if ( properties.contains( "displacement_x" ) )
01339   {
01340     layer->setDisplacementX( properties["displacement_x"].toDouble() );
01341   }
01342   if ( properties.contains( "displacement_y" ) )
01343   {
01344     layer->setDisplacementY( properties["displacement_y"].toDouble() );
01345   }
01346 
01347   if ( properties.contains( "distance_x_unit" ) )
01348   {
01349     layer->setDistanceXUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_x_unit"] ) );
01350   }
01351   if ( properties.contains( "distance_y_unit" ) )
01352   {
01353     layer->setDistanceYUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_y_unit"] ) );
01354   }
01355   if ( properties.contains( "displacement_x_unit" ) )
01356   {
01357     layer->setDisplacementXUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["displacement_x_unit"] ) );
01358   }
01359   if ( properties.contains( "displacement_y_unit" ) )
01360   {
01361     layer->setDisplacementYUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["displacement_y_unit"] ) );
01362   }
01363 
01364   //data defined properties
01365   if ( properties.contains( "distance_x_expression" ) )
01366   {
01367     layer->setDataDefinedProperty( "distance_x", properties["distance_x_expression"] );
01368   }
01369   if ( properties.contains( "distance_y_expression" ) )
01370   {
01371     layer->setDataDefinedProperty( "distance_y", properties["distance_y_expression"] );
01372   }
01373   if ( properties.contains( "displacement_x_expression" ) )
01374   {
01375     layer->setDataDefinedProperty( "displacement_x", properties["displacement_x_expression"] );
01376   }
01377   if ( properties.contains( "displacement_y_expression" ) )
01378   {
01379     layer->setDataDefinedProperty( "displacement_y", properties["displacement_y_expression"] );
01380   }
01381   return layer;
01382 }
01383 
01384 QString QgsPointPatternFillSymbolLayer::layerType() const
01385 {
01386   return "PointPatternFill";
01387 }
01388 
01389 void QgsPointPatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext& context, QBrush& brush, double distanceX, double distanceY,
01390     double displacementX, double displacementY )
01391 {
01392   //render 3 rows and columns in one go to easily incorporate displacement
01393   const QgsRenderContext& ctx = context.renderContext();
01394   double width = distanceX * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDistanceXUnit ) * 2.0;
01395   double height = distanceY * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDistanceYUnit ) * 2.0;
01396 
01397   if ( width > 10000 || height > 10000 ) //protect symbol layer from eating too much memory
01398   {
01399     QImage img;
01400     brush.setTextureImage( img );
01401     return;
01402   }
01403 
01404   QImage patternImage( width, height, QImage::Format_ARGB32 );
01405   patternImage.fill( 0 );
01406 
01407   if ( mMarkerSymbol )
01408   {
01409     QPainter p( &patternImage );
01410 
01411     //marker rendering needs context for drawing on patternImage
01412     QgsRenderContext pointRenderContext;
01413     pointRenderContext.setPainter( &p );
01414     pointRenderContext.setRasterScaleFactor( 1.0 );
01415     pointRenderContext.setScaleFactor( context.renderContext().scaleFactor() * context.renderContext().rasterScaleFactor() );
01416     QgsMapToPixel mtp( context.renderContext().mapToPixel().mapUnitsPerPixel() / context.renderContext().rasterScaleFactor() );
01417     pointRenderContext.setMapToPixel( mtp );
01418     pointRenderContext.setForceVectorOutput( false );
01419 
01420     mMarkerSymbol->startRender( pointRenderContext );
01421 
01422     //render corner points
01423     mMarkerSymbol->renderPoint( QPointF( 0, 0 ), context.feature(), pointRenderContext );
01424     mMarkerSymbol->renderPoint( QPointF( width, 0 ), context.feature(), pointRenderContext );
01425     mMarkerSymbol->renderPoint( QPointF( 0, height ), context.feature(), pointRenderContext );
01426     mMarkerSymbol->renderPoint( QPointF( width, height ), context.feature(), pointRenderContext );
01427 
01428     //render displaced points
01429     double displacementPixelX = displacementX * QgsSymbolLayerV2Utils::lineWidthScaleFactor( ctx, mDisplacementXUnit );
01430     double displacementPixelY = displacementY * QgsSymbolLayerV2Utils::lineWidthScaleFactor( ctx, mDisplacementYUnit );
01431     mMarkerSymbol->renderPoint( QPointF( width / 2.0, -displacementPixelY ), context.feature(), pointRenderContext );
01432     mMarkerSymbol->renderPoint( QPointF( displacementPixelX, height / 2.0 ), context.feature(), pointRenderContext );
01433     mMarkerSymbol->renderPoint( QPointF( width / 2.0 + displacementPixelX, height / 2.0 - displacementPixelY ), context.feature(), pointRenderContext );
01434     mMarkerSymbol->renderPoint( QPointF( width + displacementPixelX, height / 2.0 ), context.feature(), pointRenderContext );
01435     mMarkerSymbol->renderPoint( QPointF( width / 2.0, height - displacementPixelY ), context.feature(), pointRenderContext );
01436 
01437     mMarkerSymbol->stopRender( pointRenderContext );
01438   }
01439 
01440   if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
01441   {
01442     QImage transparentImage = patternImage.copy();
01443     QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
01444     brush.setTextureImage( transparentImage );
01445   }
01446   else
01447   {
01448     brush.setTextureImage( patternImage );
01449   }
01450   QTransform brushTransform;
01451   brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
01452   brush.setTransform( brushTransform );
01453 }
01454 
01455 void QgsPointPatternFillSymbolLayer::startRender( QgsSymbolV2RenderContext& context )
01456 {
01457   applyPattern( context, mBrush, mDistanceX, mDistanceY, mDisplacementX, mDisplacementY );
01458 
01459   if ( mOutline )
01460   {
01461     mOutline->startRender( context.renderContext() );
01462   }
01463   prepareExpressions( context.layer() );
01464 }
01465 
01466 void QgsPointPatternFillSymbolLayer::stopRender( QgsSymbolV2RenderContext& context )
01467 {
01468   if ( mOutline )
01469   {
01470     mOutline->stopRender( context.renderContext() );
01471   }
01472 }
01473 
01474 QgsStringMap QgsPointPatternFillSymbolLayer::properties() const
01475 {
01476   QgsStringMap propertyMap;
01477   propertyMap["distance_x"] = QString::number( mDistanceX );
01478   propertyMap["distance_y"] = QString::number( mDistanceY );
01479   propertyMap["displacement_x"] = QString::number( mDisplacementX );
01480   propertyMap["displacement_y"] = QString::number( mDisplacementY );
01481   propertyMap["distance_x_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceXUnit );
01482   propertyMap["distance_y_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceYUnit );
01483   propertyMap["displacement_x_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mDisplacementXUnit );
01484   propertyMap["displacement_y_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mDisplacementYUnit );
01485   saveDataDefinedProperties( propertyMap );
01486   return propertyMap;
01487 }
01488 
01489 QgsSymbolLayerV2* QgsPointPatternFillSymbolLayer::clone() const
01490 {
01491   QgsPointPatternFillSymbolLayer* clonedLayer = static_cast<QgsPointPatternFillSymbolLayer*>( QgsPointPatternFillSymbolLayer::create( properties() ) );
01492   if ( mMarkerSymbol )
01493   {
01494     clonedLayer->setSubSymbol( mMarkerSymbol->clone() );
01495   }
01496   copyDataDefinedProperties( clonedLayer );
01497   return clonedLayer;
01498 }
01499 
01500 void QgsPointPatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
01501 {
01502   for ( int i = 0; i < mMarkerSymbol->symbolLayerCount(); i++ )
01503   {
01504     QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
01505     if ( !props.value( "uom", "" ).isEmpty() )
01506       symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
01507     element.appendChild( symbolizerElem );
01508 
01509     // <Geometry>
01510     QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
01511 
01512     QDomElement fillElem = doc.createElement( "se:Fill" );
01513     symbolizerElem.appendChild( fillElem );
01514 
01515     QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
01516     fillElem.appendChild( graphicFillElem );
01517 
01518     // store distanceX, distanceY, displacementX, displacementY in a <VendorOption>
01519     QString dist =  QgsSymbolLayerV2Utils::encodePoint( QPointF( mDistanceX, mDistanceY ) );
01520     QDomElement distanceElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "distance", dist );
01521     symbolizerElem.appendChild( distanceElem );
01522 
01523     QgsSymbolLayerV2 *layer = mMarkerSymbol->symbolLayer( i );
01524     QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
01525     if ( !markerLayer )
01526     {
01527       QString errorMsg = QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( layer->layerType() );
01528       graphicFillElem.appendChild( doc.createComment( errorMsg ) );
01529     }
01530     else
01531     {
01532       markerLayer->writeSldMarker( doc, graphicFillElem, props );
01533     }
01534   }
01535 }
01536 
01537 QgsSymbolLayerV2* QgsPointPatternFillSymbolLayer::createFromSld( QDomElement &element )
01538 {
01539   Q_UNUSED( element );
01540   return NULL;
01541 }
01542 
01543 bool QgsPointPatternFillSymbolLayer::setSubSymbol( QgsSymbolV2* symbol )
01544 {
01545   if ( !symbol )
01546   {
01547     return false;
01548   }
01549 
01550   if ( symbol->type() == QgsSymbolV2::Marker )
01551   {
01552     QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( symbol );
01553     delete mMarkerSymbol;
01554     mMarkerSymbol = markerSymbol;
01555   }
01556   return true;
01557 }
01558 
01559 void QgsPointPatternFillSymbolLayer::applyDataDefinedSettings( const QgsSymbolV2RenderContext& context )
01560 {
01561   QgsExpression* distanceXExpression = expression( "distance_x" );
01562   QgsExpression* distanceYExpression = expression( "distance_y" );
01563   QgsExpression* displacementXExpression = expression( "displacement_x" );
01564   QgsExpression* displacementYExpression = expression( "displacement_y" );
01565   if ( !distanceXExpression && !distanceYExpression && !displacementXExpression && !displacementYExpression )
01566   {
01567     return;
01568   }
01569 
01570   double distanceX = mDistanceX;
01571   if ( distanceXExpression )
01572   {
01573     distanceX = distanceXExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
01574   }
01575   double distanceY = mDistanceY;
01576   if ( distanceYExpression )
01577   {
01578     distanceY = distanceYExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
01579   }
01580   double displacementX = mDisplacementX;
01581   if ( displacementXExpression )
01582   {
01583     displacementX = displacementXExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
01584   }
01585   double displacementY = mDisplacementY;
01586   if ( displacementYExpression )
01587   {
01588     displacementY = displacementYExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
01589   }
01590   applyPattern( context, mBrush, distanceX, distanceY, displacementX, displacementY );
01591 }
01592 
01594 
01595 
01596 QgsCentroidFillSymbolLayerV2::QgsCentroidFillSymbolLayerV2(): mMarker( NULL )
01597 {
01598   setSubSymbol( new QgsMarkerSymbolV2() );
01599 }
01600 
01601 QgsCentroidFillSymbolLayerV2::~QgsCentroidFillSymbolLayerV2()
01602 {
01603   delete mMarker;
01604 }
01605 
01606 QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::create( const QgsStringMap& properties )
01607 {
01608   Q_UNUSED( properties );
01609   return new QgsCentroidFillSymbolLayerV2();
01610 }
01611 
01612 QString QgsCentroidFillSymbolLayerV2::layerType() const
01613 {
01614   return "CentroidFill";
01615 }
01616 
01617 void QgsCentroidFillSymbolLayerV2::setColor( const QColor& color )
01618 {
01619   mMarker->setColor( color );
01620   mColor = color;
01621 }
01622 
01623 void QgsCentroidFillSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
01624 {
01625   mMarker->setAlpha( context.alpha() );
01626   mMarker->startRender( context.renderContext() );
01627 }
01628 
01629 void QgsCentroidFillSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
01630 {
01631   mMarker->stopRender( context.renderContext() );
01632 }
01633 
01634 void QgsCentroidFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
01635 {
01636   Q_UNUSED( rings );
01637 
01638   // calculate centroid
01639   double cx = 0, cy = 0;
01640   double area, sum = 0;
01641   for ( int i = points.count() - 1, j = 0; j < points.count(); i = j++ )
01642   {
01643     const QPointF& p1 = points[i];
01644     const QPointF& p2 = points[j];
01645     area = p1.x() * p2.y() - p1.y() * p2.x();
01646     sum += area;
01647     cx += ( p1.x() + p2.x() ) * area;
01648     cy += ( p1.y() + p2.y() ) * area;
01649   }
01650   sum *= 3.0;
01651   cx /= sum;
01652   cy /= sum;
01653 
01654   mMarker->renderPoint( QPointF( cx, cy ), context.feature(), context.renderContext(), -1, context.selected() );
01655 }
01656 
01657 QgsStringMap QgsCentroidFillSymbolLayerV2::properties() const
01658 {
01659   return QgsStringMap();
01660 }
01661 
01662 QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::clone() const
01663 {
01664   QgsCentroidFillSymbolLayerV2* x = new QgsCentroidFillSymbolLayerV2();
01665   x->setSubSymbol( mMarker->clone() );
01666   return x;
01667 }
01668 
01669 void QgsCentroidFillSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
01670 {
01671   // SLD 1.0 specs says: "if a line, polygon, or raster geometry is
01672   // used with PointSymbolizer, then the semantic is to use the centroid
01673   // of the geometry, or any similar representative point.
01674   mMarker->toSld( doc, element, props );
01675 }
01676 
01677 QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::createFromSld( QDomElement &element )
01678 {
01679   QgsDebugMsg( "Entered." );
01680 
01681   QgsSymbolLayerV2 *l = QgsSymbolLayerV2Utils::createMarkerLayerFromSld( element );
01682   if ( !l )
01683     return NULL;
01684 
01685   QgsSymbolLayerV2List layers;
01686   layers.append( l );
01687   QgsMarkerSymbolV2 *marker = new QgsMarkerSymbolV2( layers );
01688 
01689   QgsCentroidFillSymbolLayerV2* x = new QgsCentroidFillSymbolLayerV2();
01690   x->setSubSymbol( marker );
01691   return x;
01692 }
01693 
01694 
01695 QgsSymbolV2* QgsCentroidFillSymbolLayerV2::subSymbol()
01696 {
01697   return mMarker;
01698 }
01699 
01700 bool QgsCentroidFillSymbolLayerV2::setSubSymbol( QgsSymbolV2* symbol )
01701 {
01702   if ( symbol == NULL || symbol->type() != QgsSymbolV2::Marker )
01703   {
01704     delete symbol;
01705     return false;
01706   }
01707 
01708   delete mMarker;
01709   mMarker = static_cast<QgsMarkerSymbolV2*>( symbol );
01710   mColor = mMarker->color();
01711   return true;
01712 }
01713 
01714 QgsSymbolV2::OutputUnit QgsCentroidFillSymbolLayerV2::outputUnit() const
01715 {
01716   if ( mMarker )
01717   {
01718     return mMarker->outputUnit();
01719   }
01720   return QgsSymbolV2::Mixed; //mOutputUnit;
01721 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines