|
QGIS API Documentation
master-59fd5e0
|
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 }