Quantum GIS API Documentation  1.7.4
src/core/symbology-ng/qgsfillsymbollayerv2.cpp
Go to the documentation of this file.
00001 #include "qgsfillsymbollayerv2.h"
00002 #include "qgsmarkersymbollayerv2.h"
00003 #include "qgssymbollayerv2utils.h"
00004 
00005 #include "qgsrendercontext.h"
00006 #include "qgsproject.h"
00007 
00008 #include <QPainter>
00009 #include <QFile>
00010 #include <QSvgRenderer>
00011 
00012 QgsSimpleFillSymbolLayerV2::QgsSimpleFillSymbolLayerV2( QColor color, Qt::BrushStyle style, QColor borderColor, Qt::PenStyle borderStyle, double borderWidth )
00013     : mBrushStyle( style ), mBorderColor( borderColor ), mBorderStyle( borderStyle ), mBorderWidth( borderWidth )
00014 {
00015   mColor = color;
00016 }
00017 
00018 
00019 QgsSymbolLayerV2* QgsSimpleFillSymbolLayerV2::create( const QgsStringMap& props )
00020 {
00021   QColor color = DEFAULT_SIMPLEFILL_COLOR;
00022   Qt::BrushStyle style = DEFAULT_SIMPLEFILL_STYLE;
00023   QColor borderColor = DEFAULT_SIMPLEFILL_BORDERCOLOR;
00024   Qt::PenStyle borderStyle = DEFAULT_SIMPLEFILL_BORDERSTYLE;
00025   double borderWidth = DEFAULT_SIMPLEFILL_BORDERWIDTH;
00026   QPointF offset;
00027 
00028   if ( props.contains( "color" ) )
00029     color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
00030   if ( props.contains( "style" ) )
00031     style = QgsSymbolLayerV2Utils::decodeBrushStyle( props["style"] );
00032   if ( props.contains( "color_border" ) )
00033     borderColor = QgsSymbolLayerV2Utils::decodeColor( props["color_border"] );
00034   if ( props.contains( "style_border" ) )
00035     borderStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["style_border"] );
00036   if ( props.contains( "width_border" ) )
00037     borderWidth = props["width_border"].toDouble();
00038   if ( props.contains( "offset" ) )
00039     offset = QgsSymbolLayerV2Utils::decodePoint( props["offset"] );
00040 
00041   QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( color, style, borderColor, borderStyle, borderWidth );
00042   sl->setOffset( offset );
00043   return sl;
00044 }
00045 
00046 
00047 QString QgsSimpleFillSymbolLayerV2::layerType() const
00048 {
00049   return "SimpleFill";
00050 }
00051 
00052 void QgsSimpleFillSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
00053 {
00054   mColor.setAlphaF( context.alpha() );
00055   mBrush = QBrush( mColor, mBrushStyle );
00056 
00057   // scale brush content for printout
00058   double rasterScaleFactor = context.renderContext().rasterScaleFactor();
00059   if ( rasterScaleFactor != 1.0 )
00060   {
00061     mBrush.setMatrix( QMatrix().scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor ) );
00062   }
00063 
00064   QColor selColor = context.selectionColor();
00065   // selColor.setAlphaF( context.alpha() );
00066   mSelBrush = QBrush( selColor );
00067   if ( selectFillStyle )  mSelBrush.setStyle( mBrushStyle );
00068   mBorderColor.setAlphaF( context.alpha() );
00069   mPen = QPen( mBorderColor );
00070   mPen.setStyle( mBorderStyle );
00071   mPen.setWidthF( context.outputLineWidth( mBorderWidth ) );
00072 }
00073 
00074 void QgsSimpleFillSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
00075 {
00076 }
00077 
00078 void QgsSimpleFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
00079 {
00080   QPainter* p = context.renderContext().painter();
00081   if ( !p )
00082   {
00083     return;
00084   }
00085 
00086   p->setBrush( context.selected() ? mSelBrush : mBrush );
00087   p->setPen( mPen );
00088 
00089   if ( !mOffset.isNull() )
00090     p->translate( mOffset );
00091 
00092   _renderPolygon( p, points, rings );
00093 
00094   if ( !mOffset.isNull() )
00095     p->translate( -mOffset );
00096 }
00097 
00098 QgsStringMap QgsSimpleFillSymbolLayerV2::properties() const
00099 {
00100   QgsStringMap map;
00101   map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
00102   map["style"] = QgsSymbolLayerV2Utils::encodeBrushStyle( mBrushStyle );
00103   map["color_border"] = QgsSymbolLayerV2Utils::encodeColor( mBorderColor );
00104   map["style_border"] = QgsSymbolLayerV2Utils::encodePenStyle( mBorderStyle );
00105   map["width_border"] = QString::number( mBorderWidth );
00106   map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
00107   return map;
00108 }
00109 
00110 QgsSymbolLayerV2* QgsSimpleFillSymbolLayerV2::clone() const
00111 {
00112   QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( mColor, mBrushStyle, mBorderColor, mBorderStyle, mBorderWidth );
00113   sl->setOffset( mOffset );
00114   return sl;
00115 }
00116 
00117 //QgsSVGFillSymbolLayer
00118 
00119 QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QString& svgFilePath, double width, double angle ): mPatternWidth( width ), mOutline( 0 )
00120 {
00121   setSvgFilePath( svgFilePath );
00122   mOutlineWidth = 0.3;
00123   mAngle = angle;
00124   setSubSymbol( new QgsLineSymbolV2() );
00125 }
00126 
00127 QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QByteArray& svgData, double width, double angle ): mPatternWidth( width ),
00128     mSvgData( svgData ), mOutline( 0 )
00129 {
00130   storeViewBox();
00131   mOutlineWidth = 0.3;
00132   mAngle = angle;
00133   setSubSymbol( new QgsLineSymbolV2() );
00134 }
00135 
00136 QgsSVGFillSymbolLayer::~QgsSVGFillSymbolLayer()
00137 {
00138   delete mOutline;
00139 }
00140 
00141 void QgsSVGFillSymbolLayer::setSvgFilePath( const QString& svgPath )
00142 {
00143   QFile svgFile( svgPath );
00144   if ( svgFile.open( QFile::ReadOnly ) )
00145   {
00146     mSvgData = svgFile.readAll();
00147     storeViewBox();
00148   }
00149   mSvgFilePath = svgPath;
00150 }
00151 
00152 QgsSymbolLayerV2* QgsSVGFillSymbolLayer::create( const QgsStringMap& properties )
00153 {
00154   QByteArray data;
00155   double width = 20;
00156   QString svgFilePath;
00157   double angle = 0.0;
00158 
00159 
00160   if ( properties.contains( "width" ) )
00161   {
00162     width = properties["width"].toDouble();
00163   }
00164   if ( properties.contains( "svgFile" ) )
00165   {
00166     QString svgName = properties["svgFile"];
00167     QString savePath = QgsSvgMarkerSymbolLayerV2::symbolNameToPath( svgName );
00168     svgFilePath = ( savePath.isEmpty() ? svgName : savePath );
00169   }
00170   if ( properties.contains( "angle" ) )
00171   {
00172     angle = properties["angle"].toDouble();
00173   }
00174 
00175   if ( !svgFilePath.isEmpty() )
00176   {
00177     return new QgsSVGFillSymbolLayer( svgFilePath, width, angle );
00178   }
00179   else
00180   {
00181     if ( properties.contains( "data" ) )
00182     {
00183       data = QByteArray::fromHex( properties["data"].toLocal8Bit() );
00184     }
00185 
00186     return new QgsSVGFillSymbolLayer( data, width, angle );
00187   }
00188 }
00189 
00190 QString QgsSVGFillSymbolLayer::layerType() const
00191 {
00192   return "SVGFill";
00193 }
00194 
00195 void QgsSVGFillSymbolLayer::startRender( QgsSymbolV2RenderContext& context )
00196 {
00197   if ( mSvgViewBox.isNull() )
00198   {
00199     return;
00200   }
00201 
00202   //create QImage with appropriate dimensions
00203   int pixelWidth = context.outputPixelSize( mPatternWidth );
00204   int pixelHeight = pixelWidth / mSvgViewBox.width() * mSvgViewBox.height();
00205 
00206   QImage textureImage( pixelWidth, pixelHeight, QImage::Format_ARGB32_Premultiplied );
00207   textureImage.fill( 0 ); // transparent background
00208 
00209   //rasterise byte array to image
00210   QPainter p( &textureImage );
00211   QSvgRenderer r( mSvgData );
00212   if ( !r.isValid() )
00213   {
00214     return;
00215   }
00216 
00217   r.render( &p );
00218 
00219   if ( context.alpha() < 1.0 )
00220   {
00221     QgsSymbolLayerV2Utils::multiplyImageOpacity( &textureImage, context.alpha() );
00222   }
00223 
00224   QTransform brushTransform;
00225   brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
00226   mBrush.setTextureImage( textureImage );
00227   mBrush.setTransform( brushTransform );
00228 
00229   if ( mOutline )
00230   {
00231     mOutline->startRender( context.renderContext() );
00232   }
00233 }
00234 
00235 void QgsSVGFillSymbolLayer::stopRender( QgsSymbolV2RenderContext& context )
00236 {
00237   if ( mOutline )
00238   {
00239     mOutline->stopRender( context.renderContext() );
00240   }
00241 }
00242 
00243 void QgsSVGFillSymbolLayer::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
00244 {
00245   QPainter* p = context.renderContext().painter();
00246   if ( !p )
00247   {
00248     return;
00249   }
00250   p->setPen( QPen( Qt::NoPen ) );
00251   if ( context.selected() )
00252   {
00253     QColor selColor = context.selectionColor();
00254     if ( ! selectionIsOpaque ) selColor.setAlphaF( context.alpha() );
00255     p->setBrush( QBrush( selColor ) );
00256     _renderPolygon( p, points, rings );
00257   }
00258 
00259   if ( doubleNear( mAngle, 0.0 ) )
00260   {
00261     p->setBrush( mBrush );
00262   }
00263   else
00264   {
00265     QTransform t = mBrush.transform();
00266     t.rotate( mAngle );
00267     QBrush rotatedBrush = mBrush;
00268     rotatedBrush.setTransform( t );
00269     p->setBrush( rotatedBrush );
00270   }
00271   _renderPolygon( p, points, rings );
00272   if ( mOutline )
00273   {
00274     mOutline->renderPolyline( points, context.renderContext(), -1, selectFillBorder && context.selected() );
00275     if ( rings )
00276     {
00277       QList<QPolygonF>::const_iterator ringIt = rings->constBegin();
00278       for ( ; ringIt != rings->constEnd(); ++ringIt )
00279       {
00280         mOutline->renderPolyline( *ringIt, context.renderContext(), -1, selectFillBorder && context.selected() );
00281       }
00282     }
00283   }
00284 }
00285 
00286 QgsStringMap QgsSVGFillSymbolLayer::properties() const
00287 {
00288   QgsStringMap map;
00289   if ( !mSvgFilePath.isEmpty() )
00290   {
00291     map.insert( "svgFile", QgsSvgMarkerSymbolLayerV2::symbolPathToName( mSvgFilePath ) );
00292   }
00293   else
00294   {
00295     map.insert( "data", QString( mSvgData.toHex() ) );
00296   }
00297 
00298   map.insert( "width", QString::number( mPatternWidth ) );
00299   map.insert( "angle", QString::number( mAngle ) );
00300   return map;
00301 }
00302 
00303 QgsSymbolLayerV2* QgsSVGFillSymbolLayer::clone() const
00304 {
00305   QgsSymbolLayerV2* clonedLayer = 0;
00306   if ( !mSvgFilePath.isEmpty() )
00307   {
00308     clonedLayer = new QgsSVGFillSymbolLayer( mSvgFilePath, mPatternWidth, mAngle );
00309   }
00310   else
00311   {
00312     clonedLayer = new QgsSVGFillSymbolLayer( mSvgData, mPatternWidth, mAngle );
00313   }
00314 
00315   if ( mOutline )
00316   {
00317     clonedLayer->setSubSymbol( mOutline->clone() );
00318   }
00319   return clonedLayer;
00320 }
00321 
00322 void QgsSVGFillSymbolLayer::storeViewBox()
00323 {
00324   if ( !mSvgData.isEmpty() )
00325   {
00326     QSvgRenderer r( mSvgData );
00327     if ( r.isValid() )
00328     {
00329       mSvgViewBox = r.viewBoxF();
00330       return;
00331     }
00332   }
00333 
00334   mSvgViewBox = QRectF();
00335   return;
00336 }
00337 
00338 bool QgsSVGFillSymbolLayer::setSubSymbol( QgsSymbolV2* symbol )
00339 {
00340   if ( !symbol || symbol->type() != QgsSymbolV2::Line )
00341   {
00342     delete symbol;
00343     return false;
00344   }
00345 
00346   QgsLineSymbolV2* lineSymbol = dynamic_cast<QgsLineSymbolV2*>( symbol );
00347   if ( lineSymbol )
00348   {
00349     delete mOutline;
00350     mOutline = lineSymbol;
00351     return true;
00352   }
00353 
00354   delete symbol;
00355   return false;
00356 }
00357 
00358 
00360 
00361 
00362 QgsCentroidFillSymbolLayerV2::QgsCentroidFillSymbolLayerV2()
00363 {
00364   mMarker = NULL;
00365   setSubSymbol( new QgsMarkerSymbolV2() );
00366 }
00367 
00368 QgsCentroidFillSymbolLayerV2::~QgsCentroidFillSymbolLayerV2()
00369 {
00370   delete mMarker;
00371 }
00372 
00373 QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::create( const QgsStringMap& /*properties*/ )
00374 {
00375   return new QgsCentroidFillSymbolLayerV2();
00376 }
00377 
00378 QString QgsCentroidFillSymbolLayerV2::layerType() const
00379 {
00380   return "CentroidFill";
00381 }
00382 
00383 void QgsCentroidFillSymbolLayerV2::setColor( const QColor& color )
00384 {
00385   mMarker->setColor( color );
00386   mColor = color;
00387 }
00388 
00389 void QgsCentroidFillSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
00390 {
00391   mMarker->setAlpha( context.alpha() );
00392   mMarker->setOutputUnit( context.outputUnit() );
00393 
00394   mMarker->startRender( context.renderContext() );
00395 }
00396 
00397 void QgsCentroidFillSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
00398 {
00399   mMarker->stopRender( context.renderContext() );
00400 }
00401 
00402 void QgsCentroidFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
00403 {
00404   // calculate centroid
00405   double cx = 0, cy = 0;
00406   double area, sum = 0;
00407   for ( int i = points.count() - 1, j = 0; j < points.count(); i = j++ )
00408   {
00409     const QPointF& p1 = points[i];
00410     const QPointF& p2 = points[j];
00411     area = p1.x() * p2.y() - p1.y() * p2.x();
00412     sum += area;
00413     cx += ( p1.x() + p2.x() ) * area;
00414     cy += ( p1.y() + p2.y() ) * area;
00415   }
00416   sum *= 3.0;
00417   cx /= sum;
00418   cy /= sum;
00419 
00420   mMarker->renderPoint( QPointF( cx, cy ), context.renderContext(), -1, context.selected() );
00421 }
00422 
00423 QgsStringMap QgsCentroidFillSymbolLayerV2::properties() const
00424 {
00425   return QgsStringMap();
00426 }
00427 
00428 QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::clone() const
00429 {
00430   QgsCentroidFillSymbolLayerV2* x = new QgsCentroidFillSymbolLayerV2();
00431   x->setSubSymbol( mMarker->clone() );
00432   return x;
00433 }
00434 
00435 
00436 QgsSymbolV2* QgsCentroidFillSymbolLayerV2::subSymbol()
00437 {
00438   return mMarker;
00439 }
00440 
00441 bool QgsCentroidFillSymbolLayerV2::setSubSymbol( QgsSymbolV2* symbol )
00442 {
00443   if ( symbol == NULL || symbol->type() != QgsSymbolV2::Marker )
00444   {
00445     delete symbol;
00446     return false;
00447   }
00448 
00449   delete mMarker;
00450   mMarker = static_cast<QgsMarkerSymbolV2*>( symbol );
00451   mColor = mMarker->color();
00452   return true;
00453 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines