00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "qgsfillsymbollayerv2.h"
00016 #include "qgsmarkersymbollayerv2.h"
00017 #include "qgssymbollayerv2utils.h"
00018
00019 #include "qgsrendercontext.h"
00020 #include "qgsproject.h"
00021 #include "qgssvgcache.h"
00022 #include "qgslogger.h"
00023
00024 #include <QPainter>
00025 #include <QFile>
00026 #include <QSvgRenderer>
00027 #include <QDomDocument>
00028 #include <QDomElement>
00029
00030 QgsSimpleFillSymbolLayerV2::QgsSimpleFillSymbolLayerV2( QColor color, Qt::BrushStyle style, QColor borderColor, Qt::PenStyle borderStyle, double borderWidth )
00031 : mBrushStyle( style ), mBorderColor( borderColor ), mBorderStyle( borderStyle ), mBorderWidth( borderWidth )
00032 {
00033 mColor = color;
00034 }
00035
00036
00037 QgsSymbolLayerV2* QgsSimpleFillSymbolLayerV2::create( const QgsStringMap& props )
00038 {
00039 QColor color = DEFAULT_SIMPLEFILL_COLOR;
00040 Qt::BrushStyle style = DEFAULT_SIMPLEFILL_STYLE;
00041 QColor borderColor = DEFAULT_SIMPLEFILL_BORDERCOLOR;
00042 Qt::PenStyle borderStyle = DEFAULT_SIMPLEFILL_BORDERSTYLE;
00043 double borderWidth = DEFAULT_SIMPLEFILL_BORDERWIDTH;
00044 QPointF offset;
00045
00046 if ( props.contains( "color" ) )
00047 color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
00048 if ( props.contains( "style" ) )
00049 style = QgsSymbolLayerV2Utils::decodeBrushStyle( props["style"] );
00050 if ( props.contains( "color_border" ) )
00051 borderColor = QgsSymbolLayerV2Utils::decodeColor( props["color_border"] );
00052 if ( props.contains( "style_border" ) )
00053 borderStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["style_border"] );
00054 if ( props.contains( "width_border" ) )
00055 borderWidth = props["width_border"].toDouble();
00056 if ( props.contains( "offset" ) )
00057 offset = QgsSymbolLayerV2Utils::decodePoint( props["offset"] );
00058
00059 QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( color, style, borderColor, borderStyle, borderWidth );
00060 sl->setOffset( offset );
00061 return sl;
00062 }
00063
00064
00065 QString QgsSimpleFillSymbolLayerV2::layerType() const
00066 {
00067 return "SimpleFill";
00068 }
00069
00070 void QgsSimpleFillSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
00071 {
00072 mColor.setAlphaF( context.alpha() );
00073 mBrush = QBrush( mColor, mBrushStyle );
00074
00075
00076 double rasterScaleFactor = context.renderContext().rasterScaleFactor();
00077 if ( rasterScaleFactor != 1.0 )
00078 {
00079 mBrush.setMatrix( QMatrix().scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor ) );
00080 }
00081
00082 QColor selColor = context.selectionColor();
00083
00084 mSelBrush = QBrush( selColor );
00085 if ( selectFillStyle )
00086 mSelBrush.setStyle( mBrushStyle );
00087 mBorderColor.setAlphaF( context.alpha() );
00088 mPen = QPen( mBorderColor );
00089 mPen.setStyle( mBorderStyle );
00090 mPen.setWidthF( context.outputLineWidth( mBorderWidth ) );
00091 }
00092
00093 void QgsSimpleFillSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
00094 {
00095 Q_UNUSED( context );
00096 }
00097
00098 void QgsSimpleFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
00099 {
00100 QPainter* p = context.renderContext().painter();
00101 if ( !p )
00102 {
00103 return;
00104 }
00105
00106 p->setBrush( context.selected() ? mSelBrush : mBrush );
00107 p->setPen( mPen );
00108
00109 if ( !mOffset.isNull() )
00110 p->translate( mOffset );
00111
00112 _renderPolygon( p, points, rings );
00113
00114 if ( !mOffset.isNull() )
00115 p->translate( -mOffset );
00116 }
00117
00118 QgsStringMap QgsSimpleFillSymbolLayerV2::properties() const
00119 {
00120 QgsStringMap map;
00121 map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
00122 map["style"] = QgsSymbolLayerV2Utils::encodeBrushStyle( mBrushStyle );
00123 map["color_border"] = QgsSymbolLayerV2Utils::encodeColor( mBorderColor );
00124 map["style_border"] = QgsSymbolLayerV2Utils::encodePenStyle( mBorderStyle );
00125 map["width_border"] = QString::number( mBorderWidth );
00126 map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
00127 return map;
00128 }
00129
00130 QgsSymbolLayerV2* QgsSimpleFillSymbolLayerV2::clone() const
00131 {
00132 QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( mColor, mBrushStyle, mBorderColor, mBorderStyle, mBorderWidth );
00133 sl->setOffset( mOffset );
00134 return sl;
00135 }
00136
00137 void QgsSimpleFillSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
00138 {
00139 if ( mBrushStyle == Qt::NoBrush && mBorderStyle == Qt::NoPen )
00140 return;
00141
00142 QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
00143 if ( !props.value( "uom", "" ).isEmpty() )
00144 symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
00145 element.appendChild( symbolizerElem );
00146
00147
00148 QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
00149
00150 if ( mBrushStyle != Qt::NoBrush )
00151 {
00152
00153 QDomElement fillElem = doc.createElement( "se:Fill" );
00154 symbolizerElem.appendChild( fillElem );
00155 QgsSymbolLayerV2Utils::fillToSld( doc, fillElem, mBrushStyle, mColor );
00156 }
00157
00158 if ( mBorderStyle != Qt::NoPen )
00159 {
00160
00161 QDomElement strokeElem = doc.createElement( "se:Stroke" );
00162 symbolizerElem.appendChild( strokeElem );
00163 QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, mBorderStyle, mBorderColor, mBorderWidth );
00164 }
00165
00166
00167 QgsSymbolLayerV2Utils::createDisplacementElement( doc, symbolizerElem, mOffset );
00168 }
00169
00170 QgsSymbolLayerV2* QgsSimpleFillSymbolLayerV2::createFromSld( QDomElement &element )
00171 {
00172 QgsDebugMsg( "Entered." );
00173
00174 QColor color, borderColor;
00175 Qt::BrushStyle fillStyle;
00176 Qt::PenStyle borderStyle;
00177 double borderWidth;
00178
00179 QDomElement fillElem = element.firstChildElement( "Fill" );
00180 QgsSymbolLayerV2Utils::fillFromSld( fillElem, fillStyle, color );
00181
00182 QDomElement strokeElem = element.firstChildElement( "Stroke" );
00183 QgsSymbolLayerV2Utils::lineFromSld( strokeElem, borderStyle, borderColor, borderWidth );
00184
00185 QPointF offset;
00186 QgsSymbolLayerV2Utils::displacementFromSldElement( element, offset );
00187
00188 QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( color, fillStyle, borderColor, borderStyle, borderWidth );
00189 sl->setOffset( offset );
00190 return sl;
00191 }
00192
00193
00194
00195
00196 QgsImageFillSymbolLayer::QgsImageFillSymbolLayer(): mOutlineWidth( 0.0 ), mOutline( 0 )
00197 {
00198 setSubSymbol( new QgsLineSymbolV2() );
00199 }
00200
00201 QgsImageFillSymbolLayer::~QgsImageFillSymbolLayer()
00202 {
00203 }
00204
00205 void QgsImageFillSymbolLayer::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
00206 {
00207 QPainter* p = context.renderContext().painter();
00208 if ( !p )
00209 {
00210 return;
00211 }
00212 p->setPen( QPen( Qt::NoPen ) );
00213 if ( context.selected() )
00214 {
00215 QColor selColor = context.selectionColor();
00216 if ( ! selectionIsOpaque )
00217 selColor.setAlphaF( context.alpha() );
00218 p->setBrush( QBrush( selColor ) );
00219 _renderPolygon( p, points, rings );
00220 }
00221
00222 if ( doubleNear( mAngle, 0.0 ) )
00223 {
00224 p->setBrush( mBrush );
00225 }
00226 else
00227 {
00228 QTransform t = mBrush.transform();
00229 t.rotate( mAngle );
00230 QBrush rotatedBrush = mBrush;
00231 rotatedBrush.setTransform( t );
00232 p->setBrush( rotatedBrush );
00233 }
00234 _renderPolygon( p, points, rings );
00235 if ( mOutline )
00236 {
00237 mOutline->renderPolyline( points, context.feature(), context.renderContext(), -1, selectFillBorder && context.selected() );
00238 if ( rings )
00239 {
00240 QList<QPolygonF>::const_iterator ringIt = rings->constBegin();
00241 for ( ; ringIt != rings->constEnd(); ++ringIt )
00242 {
00243 mOutline->renderPolyline( *ringIt, context.feature(), context.renderContext(), -1, selectFillBorder && context.selected() );
00244 }
00245 }
00246 }
00247 }
00248
00249 bool QgsImageFillSymbolLayer::setSubSymbol( QgsSymbolV2* symbol )
00250 {
00251 if ( !symbol )
00252 {
00253 delete mOutline;
00254 mOutline = 0;
00255 return true;
00256 }
00257
00258 if ( symbol->type() != QgsSymbolV2::Line )
00259 {
00260 delete symbol;
00261 return false;
00262 }
00263
00264 QgsLineSymbolV2* lineSymbol = dynamic_cast<QgsLineSymbolV2*>( symbol );
00265 if ( lineSymbol )
00266 {
00267 delete mOutline;
00268 mOutline = lineSymbol;
00269 return true;
00270 }
00271
00272 delete symbol;
00273 return false;
00274 }
00275
00276
00277
00278 QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QString& svgFilePath, double width, double angle ): QgsImageFillSymbolLayer(), mPatternWidth( width )
00279 {
00280 setSvgFilePath( svgFilePath );
00281 mOutlineWidth = 0.3;
00282 mAngle = angle;
00283 setDefaultSvgParams();
00284 }
00285
00286 QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QByteArray& svgData, double width, double angle ): QgsImageFillSymbolLayer(), mPatternWidth( width ),
00287 mSvgData( svgData )
00288 {
00289 storeViewBox();
00290 mOutlineWidth = 0.3;
00291 mAngle = angle;
00292 setSubSymbol( new QgsLineSymbolV2() );
00293 setDefaultSvgParams();
00294 }
00295
00296 QgsSVGFillSymbolLayer::~QgsSVGFillSymbolLayer()
00297 {
00298 delete mOutline;
00299 }
00300
00301 void QgsSVGFillSymbolLayer::setSvgFilePath( const QString& svgPath )
00302 {
00303 QFile svgFile( svgPath );
00304 if ( svgFile.open( QFile::ReadOnly ) )
00305 {
00306 mSvgData = svgFile.readAll();
00307
00308 storeViewBox();
00309 }
00310 mSvgFilePath = svgPath;
00311 setDefaultSvgParams();
00312 }
00313
00314 QgsSymbolLayerV2* QgsSVGFillSymbolLayer::create( const QgsStringMap& properties )
00315 {
00316 QByteArray data;
00317 double width = 20;
00318 QString svgFilePath;
00319 double angle = 0.0;
00320
00321 if ( properties.contains( "width" ) )
00322 {
00323 width = properties["width"].toDouble();
00324 }
00325 if ( properties.contains( "svgFile" ) )
00326 {
00327 QString svgName = properties["svgFile"];
00328 QString savePath = QgsSvgMarkerSymbolLayerV2::symbolNameToPath( svgName );
00329 svgFilePath = ( savePath.isEmpty() ? svgName : savePath );
00330 }
00331 if ( properties.contains( "angle" ) )
00332 {
00333 angle = properties["angle"].toDouble();
00334 }
00335
00336 QgsSVGFillSymbolLayer* symbolLayer = 0;
00337 if ( !svgFilePath.isEmpty() )
00338 {
00339 symbolLayer = new QgsSVGFillSymbolLayer( svgFilePath, width, angle );
00340 }
00341 else
00342 {
00343 if ( properties.contains( "data" ) )
00344 {
00345 data = QByteArray::fromHex( properties["data"].toLocal8Bit() );
00346 }
00347 symbolLayer = new QgsSVGFillSymbolLayer( data, width, angle );
00348 }
00349
00350
00351 if ( properties.contains( "svgFillColor" ) )
00352 {
00353 symbolLayer->setSvgFillColor( QColor( properties["svgFillColor"] ) );
00354 }
00355 if ( properties.contains( "svgOutlineColor" ) )
00356 {
00357 symbolLayer->setSvgOutlineColor( QColor( properties["svgOutlineColor"] ) );
00358 }
00359 if ( properties.contains( "svgOutlineWidth" ) )
00360 {
00361 symbolLayer->setSvgOutlineWidth( properties["svgOutlineWidth"].toDouble() );
00362 }
00363
00364
00365 return symbolLayer;
00366 }
00367
00368 QString QgsSVGFillSymbolLayer::layerType() const
00369 {
00370 return "SVGFill";
00371 }
00372
00373 void QgsSVGFillSymbolLayer::startRender( QgsSymbolV2RenderContext& context )
00374 {
00375 if ( mSvgViewBox.isNull() )
00376 {
00377 return;
00378 }
00379
00380 int size = context.outputPixelSize( mPatternWidth );
00381 const QImage& patternImage = QgsSvgCache::instance()->svgAsImage( mSvgFilePath, size, mSvgFillColor, mSvgOutlineColor, mSvgOutlineWidth,
00382 context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() );
00383 QTransform brushTransform;
00384 brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
00385 if ( !doubleNear( context.alpha(), 1.0 ) )
00386 {
00387 QImage transparentImage = patternImage.copy();
00388 QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
00389 mBrush.setTextureImage( transparentImage );
00390 }
00391 else
00392 {
00393 mBrush.setTextureImage( patternImage );
00394 }
00395 mBrush.setTransform( brushTransform );
00396
00397 if ( mOutline )
00398 {
00399 mOutline->startRender( context.renderContext() );
00400 }
00401 }
00402
00403 void QgsSVGFillSymbolLayer::stopRender( QgsSymbolV2RenderContext& context )
00404 {
00405 if ( mOutline )
00406 {
00407 mOutline->stopRender( context.renderContext() );
00408 }
00409 }
00410
00411 QgsStringMap QgsSVGFillSymbolLayer::properties() const
00412 {
00413 QgsStringMap map;
00414 if ( !mSvgFilePath.isEmpty() )
00415 {
00416 map.insert( "svgFile", QgsSvgMarkerSymbolLayerV2::symbolPathToName( mSvgFilePath ) );
00417 }
00418 else
00419 {
00420 map.insert( "data", QString( mSvgData.toHex() ) );
00421 }
00422
00423 map.insert( "width", QString::number( mPatternWidth ) );
00424 map.insert( "angle", QString::number( mAngle ) );
00425
00426
00427 map.insert( "svgFillColor", mSvgFillColor.name() );
00428 map.insert( "svgOutlineColor", mSvgOutlineColor.name() );
00429 map.insert( "svgOutlineWidth", QString::number( mSvgOutlineWidth ) );
00430
00431 return map;
00432 }
00433
00434 QgsSymbolLayerV2* QgsSVGFillSymbolLayer::clone() const
00435 {
00436 QgsSymbolLayerV2* clonedLayer = 0;
00437 if ( !mSvgFilePath.isEmpty() )
00438 {
00439 clonedLayer = new QgsSVGFillSymbolLayer( mSvgFilePath, mPatternWidth, mAngle );
00440 QgsSVGFillSymbolLayer* sl = static_cast<QgsSVGFillSymbolLayer*>( clonedLayer );
00441 sl->setSvgFillColor( mSvgFillColor );
00442 sl->setSvgOutlineColor( mSvgOutlineColor );
00443 sl->setSvgOutlineWidth( mSvgOutlineWidth );
00444 }
00445 else
00446 {
00447 clonedLayer = new QgsSVGFillSymbolLayer( mSvgData, mPatternWidth, mAngle );
00448 }
00449
00450 if ( mOutline )
00451 {
00452 clonedLayer->setSubSymbol( mOutline->clone() );
00453 }
00454 return clonedLayer;
00455 }
00456
00457 void QgsSVGFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
00458 {
00459 QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
00460 if ( !props.value( "uom", "" ).isEmpty() )
00461 symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
00462 element.appendChild( symbolizerElem );
00463
00464 QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
00465
00466 QDomElement fillElem = doc.createElement( "se:Fill" );
00467 symbolizerElem.appendChild( fillElem );
00468
00469 QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
00470 fillElem.appendChild( graphicFillElem );
00471
00472 QDomElement graphicElem = doc.createElement( "se:Graphic" );
00473 graphicFillElem.appendChild( graphicElem );
00474
00475 if ( !mSvgFilePath.isEmpty() )
00476 {
00477 QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mSvgFilePath, "image/svg+xml", mSvgFillColor, mPatternWidth );
00478 }
00479 else
00480 {
00481
00482
00483 symbolizerElem.appendChild( doc.createComment( "SVG from data not implemented yet" ) );
00484 }
00485
00486 if ( mSvgOutlineColor.isValid() || mSvgOutlineWidth >= 0 )
00487 {
00488 QgsSymbolLayerV2Utils::lineToSld( doc, graphicElem, Qt::SolidLine, mSvgOutlineColor, mSvgOutlineWidth );
00489 }
00490
00491
00492 QString angleFunc;
00493 bool ok;
00494 double angle = props.value( "angle", "0" ).toDouble( &ok );
00495 if ( !ok )
00496 {
00497 angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
00498 }
00499 else if ( angle + mAngle != 0 )
00500 {
00501 angleFunc = QString::number( angle + mAngle );
00502 }
00503 QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
00504
00505 if ( mOutline )
00506 {
00507
00508
00509
00510 mOutline->toSld( doc, element, props );
00511 }
00512 }
00513
00514 QgsSymbolLayerV2* QgsSVGFillSymbolLayer::createFromSld( QDomElement &element )
00515 {
00516 QgsDebugMsg( "Entered." );
00517
00518 QString path, mimeType;
00519 QColor fillColor, borderColor;
00520 Qt::PenStyle penStyle;
00521 double size, borderWidth;
00522
00523 QDomElement fillElem = element.firstChildElement( "Fill" );
00524 if ( fillElem.isNull() )
00525 return NULL;
00526
00527 QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
00528 if ( graphicFillElem.isNull() )
00529 return NULL;
00530
00531 QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
00532 if ( graphicElem.isNull() )
00533 return NULL;
00534
00535 if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
00536 return NULL;
00537
00538 if ( mimeType != "image/svg+xml" )
00539 return NULL;
00540
00541 QgsSymbolLayerV2Utils::lineFromSld( graphicElem, penStyle, borderColor, borderWidth );
00542
00543 double angle = 0.0;
00544 QString angleFunc;
00545 if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
00546 {
00547 bool ok;
00548 double d = angleFunc.toDouble( &ok );
00549 if ( ok )
00550 angle = d;
00551 }
00552
00553 QgsSVGFillSymbolLayer* sl = new QgsSVGFillSymbolLayer( path, size, angle );
00554 sl->setSvgFillColor( fillColor );
00555 sl->setSvgOutlineColor( borderColor );
00556 sl->setSvgOutlineWidth( borderWidth );
00557
00558
00559 QDomElement strokeElem = element.firstChildElement( "Stroke" );
00560 if ( !strokeElem.isNull() )
00561 {
00562 QgsSymbolLayerV2 *l = QgsSymbolLayerV2Utils::createLineLayerFromSld( strokeElem );
00563 if ( l )
00564 {
00565 QgsSymbolLayerV2List layers;
00566 layers.append( l );
00567 sl->setSubSymbol( new QgsLineSymbolV2( layers ) );
00568 }
00569 }
00570
00571 return sl;
00572 }
00573
00574 void QgsSVGFillSymbolLayer::storeViewBox()
00575 {
00576 if ( !mSvgData.isEmpty() )
00577 {
00578 QSvgRenderer r( mSvgData );
00579 if ( r.isValid() )
00580 {
00581 mSvgViewBox = r.viewBoxF();
00582 return;
00583 }
00584 }
00585
00586 mSvgViewBox = QRectF();
00587 return;
00588 }
00589
00590 void QgsSVGFillSymbolLayer::setDefaultSvgParams()
00591 {
00592
00593 mSvgFillColor = QColor( 0, 0, 0 );
00594 mSvgOutlineColor = QColor( 0, 0, 0 );
00595 mSvgOutlineWidth = 0.3;
00596
00597 if ( mSvgFilePath.isEmpty() )
00598 {
00599 return;
00600 }
00601
00602 bool hasFillParam, hasOutlineParam, hasOutlineWidthParam;
00603 QColor defaultFillColor, defaultOutlineColor;
00604 double defaultOutlineWidth;
00605 QgsSvgCache::instance()->containsParams( mSvgFilePath, hasFillParam, defaultFillColor, hasOutlineParam, defaultOutlineColor, hasOutlineWidthParam,
00606 defaultOutlineWidth );
00607
00608 if ( hasFillParam )
00609 {
00610 mSvgFillColor = defaultFillColor;
00611 }
00612 if ( hasOutlineParam )
00613 {
00614 mSvgOutlineColor = defaultOutlineColor;
00615 }
00616 if ( hasOutlineWidthParam )
00617 {
00618 mSvgOutlineWidth = defaultOutlineWidth;
00619 }
00620 }
00621
00622 QgsLinePatternFillSymbolLayer::QgsLinePatternFillSymbolLayer(): QgsImageFillSymbolLayer()
00623 {
00624 }
00625
00626 QgsLinePatternFillSymbolLayer::~QgsLinePatternFillSymbolLayer()
00627 {
00628 }
00629
00630 QgsSymbolLayerV2* QgsLinePatternFillSymbolLayer::create( const QgsStringMap& properties )
00631 {
00632 QgsLinePatternFillSymbolLayer* patternLayer = new QgsLinePatternFillSymbolLayer();
00633
00634
00635 double lineAngle = 45;
00636 double distance = 5;
00637 double lineWidth = 0.5;
00638 QColor color( Qt::black );
00639 double offset = 0.0;
00640
00641 if ( properties.contains( "lineangle" ) )
00642 {
00643 lineAngle = properties["lineangle"].toDouble();
00644 }
00645 patternLayer->setLineAngle( lineAngle );
00646
00647 if ( properties.contains( "distance" ) )
00648 {
00649 distance = properties["distance"].toDouble();
00650 }
00651 patternLayer->setDistance( distance );
00652
00653 if ( properties.contains( "linewidth" ) )
00654 {
00655 lineWidth = properties["linewidth"].toDouble();
00656 }
00657 patternLayer->setLineWidth( lineWidth );
00658
00659 if ( properties.contains( "color" ) )
00660 {
00661 color = QgsSymbolLayerV2Utils::decodeColor( properties["color"] );
00662 }
00663 patternLayer->setColor( color );
00664
00665 if ( properties.contains( "offset" ) )
00666 {
00667 offset = properties["offset"].toDouble();
00668 }
00669 patternLayer->setOffset( offset );
00670 return patternLayer;
00671 }
00672
00673 QString QgsLinePatternFillSymbolLayer::layerType() const
00674 {
00675 return "LinePatternFill";
00676 }
00677
00678 void QgsLinePatternFillSymbolLayer::startRender( QgsSymbolV2RenderContext& context )
00679 {
00680 double outlinePixelWidth = context.outputPixelSize( mLineWidth );
00681 double outputPixelDist = context.outputPixelSize( mDistance );
00682 double outputPixelOffset = context.outputPixelSize( mOffset );
00683
00684
00685 int height, width;
00686 if ( doubleNear( mLineAngle, 0 ) || doubleNear( mLineAngle, 360 ) || doubleNear( mLineAngle, 90 ) || doubleNear( mLineAngle, 180 ) || doubleNear( mLineAngle, 270 ) )
00687 {
00688 height = outputPixelDist;
00689 width = height;
00690 }
00691 else
00692 {
00693 height = qAbs( outputPixelDist / cos( mLineAngle * M_PI / 180 ) );
00694 width = qAbs( height / tan( mLineAngle * M_PI / 180 ) );
00695 }
00696
00697
00698 int dx = 0;
00699 int dy = 0;
00700
00701 QImage patternImage( width, height, QImage::Format_ARGB32 );
00702 patternImage.fill( 0 );
00703 QPainter p( &patternImage );
00704
00705 p.setRenderHint( QPainter::Antialiasing, true );
00706 QPen pen( mColor );
00707 pen.setWidthF( outlinePixelWidth );
00708 pen.setCapStyle( Qt::FlatCap );
00709 p.setPen( pen );
00710
00711 QPoint p1, p2, p3, p4, p5, p6;
00712 if ( doubleNear( mLineAngle, 0.0 ) || doubleNear( mLineAngle, 360.0 ) || doubleNear( mLineAngle, 180.0 ) )
00713 {
00714 p1 = QPoint( 0, height );
00715 p2 = QPoint( width, height );
00716 p3 = QPoint( 0, 0 );
00717 p4 = QPoint( width, 0 );
00718 p5 = QPoint( 0, 2 * height );
00719 p6 = QPoint( width, 2 * height );
00720 }
00721 else if ( doubleNear( mLineAngle, 90.0 ) || doubleNear( mLineAngle, 270.0 ) )
00722 {
00723 p1 = QPoint( 0, height );
00724 p2 = QPoint( 0, 0 );
00725 p3 = QPoint( width, height );
00726 p4 = QPoint( width, 0 );
00727 p5 = QPoint( -width, height );
00728 p6 = QPoint( -width, 0 );
00729 }
00730 else if (( mLineAngle > 0 && mLineAngle < 90 ) || ( mLineAngle > 180 && mLineAngle < 270 ) )
00731 {
00732 dx = outputPixelDist * cos(( 90 - mLineAngle ) * M_PI / 180.0 );
00733 dy = outputPixelDist * sin(( 90 - mLineAngle ) * M_PI / 180.0 );
00734 p1 = QPoint( 0, height );
00735 p2 = QPoint( width, 0 );
00736 p3 = QPoint( -dx, height - dy );
00737 p4 = QPoint( width - dx, -dy );
00738 p5 = QPoint( dx, height + dy );
00739 p6 = QPoint( width + dx, dy );
00740 }
00741 else if (( mLineAngle < 180 ) || ( mLineAngle > 270 && mLineAngle < 360 ) )
00742 {
00743 dy = outputPixelDist * cos(( 180 - mLineAngle ) * M_PI / 180 );
00744 dx = outputPixelDist * sin(( 180 - mLineAngle ) * M_PI / 180 );
00745 p1 = QPoint( width, height );
00746 p2 = QPoint( 0, 0 );
00747 p5 = QPoint( width + dx, height - dy );
00748 p6 = QPoint( p5.x() - width, p5.y() - height );
00749 p3 = QPoint( width - dx, height + dy );
00750 p4 = QPoint( p3.x() - width, p3.y() - height );
00751 }
00752
00753 if ( !doubleNear( mOffset, 0.0 ) )
00754 {
00755 QPointF tempPt;
00756 tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p3, outputPixelDist + outputPixelOffset );
00757 p3 = QPoint( tempPt.x(), tempPt.y() );
00758 tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p4, outputPixelDist + outputPixelOffset );
00759 p4 = QPoint( tempPt.x(), tempPt.y() );
00760 tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p5, outputPixelDist - outputPixelOffset );
00761 p5 = QPoint( tempPt.x(), tempPt.y() );
00762 tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p6, outputPixelDist - outputPixelOffset );
00763 p6 = QPoint( tempPt.x(), tempPt.y() );
00764
00765
00766 tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p3, outputPixelOffset ).toPoint();
00767 p1 = QPoint( tempPt.x(), tempPt.y() );
00768 tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p4, outputPixelOffset ).toPoint();
00769 p2 = QPoint( tempPt.x(), tempPt.y() );;
00770 }
00771
00772 p.drawLine( p1, p2 );
00773 p.drawLine( p3, p4 );
00774 p.drawLine( p5, p6 );
00775 p.end();
00776
00777
00778 if ( !doubleNear( context.alpha(), 1.0 ) )
00779 {
00780 QImage transparentImage = patternImage.copy();
00781 QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
00782 mBrush.setTextureImage( transparentImage );
00783 }
00784 else
00785 {
00786 mBrush.setTextureImage( patternImage );
00787 }
00788
00789 QTransform brushTransform;
00790 brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
00791 mBrush.setTransform( brushTransform );
00792
00793 if ( mOutline )
00794 {
00795 mOutline->startRender( context.renderContext() );
00796 }
00797 }
00798
00799 void QgsLinePatternFillSymbolLayer::stopRender( QgsSymbolV2RenderContext & )
00800 {
00801 }
00802
00803 QgsStringMap QgsLinePatternFillSymbolLayer::properties() const
00804 {
00805 QgsStringMap map;
00806 map.insert( "lineangle", QString::number( mLineAngle ) );
00807 map.insert( "distance", QString::number( mDistance ) );
00808 map.insert( "linewidth", QString::number( mLineWidth ) );
00809 map.insert( "color", QgsSymbolLayerV2Utils::encodeColor( mColor ) );
00810 map.insert( "offset", QString::number( mOffset ) );
00811 return map;
00812 }
00813
00814 QgsSymbolLayerV2* QgsLinePatternFillSymbolLayer::clone() const
00815 {
00816 QgsSymbolLayerV2* clonedLayer = QgsLinePatternFillSymbolLayer::create( properties() );
00817 if ( mOutline )
00818 {
00819 clonedLayer->setSubSymbol( mOutline->clone() );
00820 }
00821 return clonedLayer;
00822 }
00823
00824 void QgsLinePatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
00825 {
00826 QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
00827 if ( !props.value( "uom", "" ).isEmpty() )
00828 symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
00829 element.appendChild( symbolizerElem );
00830
00831
00832 QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
00833
00834 QDomElement fillElem = doc.createElement( "se:Fill" );
00835 symbolizerElem.appendChild( fillElem );
00836
00837 QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
00838 fillElem.appendChild( graphicFillElem );
00839
00840 QDomElement graphicElem = doc.createElement( "se:Graphic" );
00841 graphicFillElem.appendChild( graphicElem );
00842
00843 QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, "horline", QColor(), mColor, mLineWidth, mDistance );
00844
00845
00846 QString angleFunc;
00847 bool ok;
00848 double angle = props.value( "angle", "0" ).toDouble( &ok );
00849 if ( !ok )
00850 {
00851 angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mLineAngle );
00852 }
00853 else if ( angle + mLineAngle != 0 )
00854 {
00855 angleFunc = QString::number( angle + mLineAngle );
00856 }
00857 QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
00858
00859
00860 QPointF lineOffset( qSin( mLineAngle ) * mOffset, qCos( mLineAngle ) * mOffset );
00861 QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, lineOffset );
00862 }
00863
00864 QgsSymbolLayerV2* QgsLinePatternFillSymbolLayer::createFromSld( QDomElement &element )
00865 {
00866 Q_UNUSED( element );
00867 return NULL;
00868 }
00869
00871
00872 QgsPointPatternFillSymbolLayer::QgsPointPatternFillSymbolLayer(): QgsImageFillSymbolLayer(), mMarkerSymbol( 0 ), mDistanceX( 15 ),
00873 mDistanceY( 15 ), mDisplacementX( 0 ), mDisplacementY( 0 )
00874 {
00875 mDistanceX = 15;
00876 mDistanceY = 15;
00877 mDisplacementX = 0;
00878 mDisplacementY = 0;
00879 setSubSymbol( new QgsMarkerSymbolV2() );
00880 QgsImageFillSymbolLayer::setSubSymbol( 0 );
00881 }
00882
00883 QgsPointPatternFillSymbolLayer::~QgsPointPatternFillSymbolLayer()
00884 {
00885 }
00886
00887 QgsSymbolLayerV2* QgsPointPatternFillSymbolLayer::create( const QgsStringMap& properties )
00888 {
00889 QgsPointPatternFillSymbolLayer* layer = new QgsPointPatternFillSymbolLayer();
00890 if ( properties.contains( "distance_x" ) )
00891 {
00892 layer->setDistanceX( properties["distance_x"].toDouble() );
00893 }
00894 if ( properties.contains( "distance_y" ) )
00895 {
00896 layer->setDistanceY( properties["distance_y"].toDouble() );
00897 }
00898 if ( properties.contains( "displacement_x" ) )
00899 {
00900 layer->setDisplacementX( properties["displacement_x"].toDouble() );
00901 }
00902 if ( properties.contains( "displacement_y" ) )
00903 {
00904 layer->setDisplacementY( properties["displacement_y"].toDouble() );
00905 }
00906 return layer;
00907 }
00908
00909 QString QgsPointPatternFillSymbolLayer::layerType() const
00910 {
00911 return "PointPatternFill";
00912 }
00913
00914 void QgsPointPatternFillSymbolLayer::startRender( QgsSymbolV2RenderContext& context )
00915 {
00916
00917 double width = context.outputPixelSize( mDistanceX ) * 2.0;
00918 double height = context.outputPixelSize( mDistanceY ) * 2.0;
00919
00920 QImage patternImage( width, height, QImage::Format_ARGB32 );
00921 patternImage.fill( 0 );
00922
00923 if ( mMarkerSymbol )
00924 {
00925 QPainter p( &patternImage );
00926
00927
00928 QgsRenderContext pointRenderContext;
00929 pointRenderContext.setPainter( &p );
00930 pointRenderContext.setRasterScaleFactor( 1.0 );
00931 pointRenderContext.setScaleFactor( context.renderContext().scaleFactor() * context.renderContext().rasterScaleFactor() );
00932 QgsMapToPixel mtp( context.renderContext().mapToPixel().mapUnitsPerPixel() / context.renderContext().rasterScaleFactor() );
00933 pointRenderContext.setMapToPixel( mtp );
00934 pointRenderContext.setForceVectorOutput( false );
00935
00936 mMarkerSymbol->setOutputUnit( context.outputUnit() );
00937 mMarkerSymbol->startRender( pointRenderContext );
00938
00939
00940 mMarkerSymbol->renderPoint( QPointF( 0, 0 ), context.feature(), pointRenderContext );
00941 mMarkerSymbol->renderPoint( QPointF( width, 0 ), context.feature(), pointRenderContext );
00942 mMarkerSymbol->renderPoint( QPointF( 0, height ), context.feature(), pointRenderContext );
00943 mMarkerSymbol->renderPoint( QPointF( width, height ), context.feature(), pointRenderContext );
00944
00945
00946 double displacementPixelX = context.outputPixelSize( mDisplacementX );
00947 double displacementPixelY = context.outputPixelSize( mDisplacementY );
00948 mMarkerSymbol->renderPoint( QPointF( width / 2.0, -displacementPixelY ), context.feature(), pointRenderContext );
00949 mMarkerSymbol->renderPoint( QPointF( displacementPixelX, height / 2.0 ), context.feature(), pointRenderContext );
00950 mMarkerSymbol->renderPoint( QPointF( width / 2.0 + displacementPixelX, height / 2.0 - displacementPixelY ), context.feature(), pointRenderContext );
00951 mMarkerSymbol->renderPoint( QPointF( width + displacementPixelX, height / 2.0 ), context.feature(), pointRenderContext );
00952 mMarkerSymbol->renderPoint( QPointF( width / 2.0, height - displacementPixelY ), context.feature(), pointRenderContext );
00953
00954 mMarkerSymbol->stopRender( pointRenderContext );
00955 }
00956
00957 if ( !doubleNear( context.alpha(), 1.0 ) )
00958 {
00959 QImage transparentImage = patternImage.copy();
00960 QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
00961 mBrush.setTextureImage( transparentImage );
00962 }
00963 else
00964 {
00965 mBrush.setTextureImage( patternImage );
00966 }
00967 QTransform brushTransform;
00968 brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
00969 mBrush.setTransform( brushTransform );
00970
00971 if ( mOutline )
00972 {
00973 mOutline->startRender( context.renderContext() );
00974 }
00975 }
00976
00977 void QgsPointPatternFillSymbolLayer::stopRender( QgsSymbolV2RenderContext& context )
00978 {
00979 if ( mOutline )
00980 {
00981 mOutline->stopRender( context.renderContext() );
00982 }
00983 }
00984
00985 QgsStringMap QgsPointPatternFillSymbolLayer::properties() const
00986 {
00987 QgsStringMap propertyMap;
00988 propertyMap["distance_x"] = QString::number( mDistanceX );
00989 propertyMap["distance_y"] = QString::number( mDistanceY );
00990 propertyMap["displacement_x"] = QString::number( mDisplacementX );
00991 propertyMap["displacement_y"] = QString::number( mDisplacementY );
00992 return propertyMap;
00993 }
00994
00995 QgsSymbolLayerV2* QgsPointPatternFillSymbolLayer::clone() const
00996 {
00997 QgsSymbolLayerV2* clonedLayer = QgsPointPatternFillSymbolLayer::create( properties() );
00998 if ( mMarkerSymbol )
00999 {
01000 clonedLayer->setSubSymbol( mMarkerSymbol->clone() );
01001 }
01002 return clonedLayer;
01003 }
01004
01005 void QgsPointPatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
01006 {
01007 for ( int i = 0; i < mMarkerSymbol->symbolLayerCount(); i++ )
01008 {
01009 QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
01010 if ( !props.value( "uom", "" ).isEmpty() )
01011 symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
01012 element.appendChild( symbolizerElem );
01013
01014
01015 QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
01016
01017 QDomElement fillElem = doc.createElement( "se:Fill" );
01018 symbolizerElem.appendChild( fillElem );
01019
01020 QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
01021 fillElem.appendChild( graphicFillElem );
01022
01023
01024 QString dist = QgsSymbolLayerV2Utils::encodePoint( QPointF( mDistanceX, mDistanceY ) );
01025 QDomElement distanceElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "distance", dist );
01026 symbolizerElem.appendChild( distanceElem );
01027
01028 QgsSymbolLayerV2 *layer = mMarkerSymbol->symbolLayer( i );
01029 QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
01030 if ( !markerLayer )
01031 {
01032 QString errorMsg = QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( layer->layerType() );
01033 graphicFillElem.appendChild( doc.createComment( errorMsg ) );
01034 }
01035 else
01036 {
01037 markerLayer->writeSldMarker( doc, graphicFillElem, props );
01038 }
01039 }
01040 }
01041
01042 QgsSymbolLayerV2* QgsPointPatternFillSymbolLayer::createFromSld( QDomElement &element )
01043 {
01044 Q_UNUSED( element );
01045 return NULL;
01046 }
01047
01048 bool QgsPointPatternFillSymbolLayer::setSubSymbol( QgsSymbolV2* symbol )
01049 {
01050 if ( !symbol )
01051 {
01052 return false;
01053 }
01054
01055 if ( symbol->type() == QgsSymbolV2::Marker )
01056 {
01057 QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( symbol );
01058 delete mMarkerSymbol;
01059 mMarkerSymbol = markerSymbol;
01060 }
01061 return true;
01062 }
01063
01065
01066
01067 QgsCentroidFillSymbolLayerV2::QgsCentroidFillSymbolLayerV2()
01068 {
01069 mMarker = NULL;
01070 setSubSymbol( new QgsMarkerSymbolV2() );
01071 }
01072
01073 QgsCentroidFillSymbolLayerV2::~QgsCentroidFillSymbolLayerV2()
01074 {
01075 delete mMarker;
01076 }
01077
01078 QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::create( const QgsStringMap& )
01079 {
01080 return new QgsCentroidFillSymbolLayerV2();
01081 }
01082
01083 QString QgsCentroidFillSymbolLayerV2::layerType() const
01084 {
01085 return "CentroidFill";
01086 }
01087
01088 void QgsCentroidFillSymbolLayerV2::setColor( const QColor& color )
01089 {
01090 mMarker->setColor( color );
01091 mColor = color;
01092 }
01093
01094 void QgsCentroidFillSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
01095 {
01096 mMarker->setAlpha( context.alpha() );
01097 mMarker->setOutputUnit( context.outputUnit() );
01098
01099 mMarker->startRender( context.renderContext() );
01100 }
01101
01102 void QgsCentroidFillSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
01103 {
01104 mMarker->stopRender( context.renderContext() );
01105 }
01106
01107 void QgsCentroidFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
01108 {
01109 Q_UNUSED( rings );
01110
01111
01112 double cx = 0, cy = 0;
01113 double area, sum = 0;
01114 for ( int i = points.count() - 1, j = 0; j < points.count(); i = j++ )
01115 {
01116 const QPointF& p1 = points[i];
01117 const QPointF& p2 = points[j];
01118 area = p1.x() * p2.y() - p1.y() * p2.x();
01119 sum += area;
01120 cx += ( p1.x() + p2.x() ) * area;
01121 cy += ( p1.y() + p2.y() ) * area;
01122 }
01123 sum *= 3.0;
01124 cx /= sum;
01125 cy /= sum;
01126
01127 mMarker->renderPoint( QPointF( cx, cy ), context.feature(), context.renderContext(), -1, context.selected() );
01128 }
01129
01130 QgsStringMap QgsCentroidFillSymbolLayerV2::properties() const
01131 {
01132 return QgsStringMap();
01133 }
01134
01135 QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::clone() const
01136 {
01137 QgsCentroidFillSymbolLayerV2* x = new QgsCentroidFillSymbolLayerV2();
01138 x->setSubSymbol( mMarker->clone() );
01139 return x;
01140 }
01141
01142 void QgsCentroidFillSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
01143 {
01144
01145
01146
01147 mMarker->toSld( doc, element, props );
01148 }
01149
01150 QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::createFromSld( QDomElement &element )
01151 {
01152 QgsDebugMsg( "Entered." );
01153
01154 QgsSymbolLayerV2 *l = QgsSymbolLayerV2Utils::createMarkerLayerFromSld( element );
01155 if ( !l )
01156 return NULL;
01157
01158 QgsSymbolLayerV2List layers;
01159 layers.append( l );
01160 QgsMarkerSymbolV2 *marker = new QgsMarkerSymbolV2( layers );
01161
01162 QgsCentroidFillSymbolLayerV2* x = new QgsCentroidFillSymbolLayerV2();
01163 x->setSubSymbol( marker );
01164 return x;
01165 }
01166
01167
01168 QgsSymbolV2* QgsCentroidFillSymbolLayerV2::subSymbol()
01169 {
01170 return mMarker;
01171 }
01172
01173 bool QgsCentroidFillSymbolLayerV2::setSubSymbol( QgsSymbolV2* symbol )
01174 {
01175 if ( symbol == NULL || symbol->type() != QgsSymbolV2::Marker )
01176 {
01177 delete symbol;
01178 return false;
01179 }
01180
01181 delete mMarker;
01182 mMarker = static_cast<QgsMarkerSymbolV2*>( symbol );
01183 mColor = mMarker->color();
01184 return true;
01185 }