QGIS API Documentation  master-59fd5e0
src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002     qgsmarkersymbollayerv2.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 
00016 #include "qgsmarkersymbollayerv2.h"
00017 #include "qgssymbollayerv2utils.h"
00018 
00019 #include "qgsexpression.h"
00020 #include "qgsrendercontext.h"
00021 #include "qgslogger.h"
00022 #include "qgssvgcache.h"
00023 
00024 #include <QPainter>
00025 #include <QSvgRenderer>
00026 #include <QFileInfo>
00027 #include <QDir>
00028 #include <QDomDocument>
00029 #include <QDomElement>
00030 
00031 #include <cmath>
00032 
00034 
00035 QgsSimpleMarkerSymbolLayerV2::QgsSimpleMarkerSymbolLayerV2( QString name, QColor color, QColor borderColor, double size, double angle, QgsSymbolV2::ScaleMethod scaleMethod )
00036     : mOutlineWidth( 0 ), mOutlineWidthUnit( QgsSymbolV2::MM )
00037 {
00038   mName = name;
00039   mColor = color;
00040   mBorderColor = borderColor;
00041   mSize = size;
00042   mAngle = angle;
00043   mOffset = QPointF( 0, 0 );
00044   mScaleMethod = scaleMethod;
00045   mSizeUnit = QgsSymbolV2::MM;
00046   mOffsetUnit = QgsSymbolV2::MM;
00047 }
00048 
00049 QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::create( const QgsStringMap& props )
00050 {
00051   QString name = DEFAULT_SIMPLEMARKER_NAME;
00052   QColor color = DEFAULT_SIMPLEMARKER_COLOR;
00053   QColor borderColor = DEFAULT_SIMPLEMARKER_BORDERCOLOR;
00054   double size = DEFAULT_SIMPLEMARKER_SIZE;
00055   double angle = DEFAULT_SIMPLEMARKER_ANGLE;
00056   QgsSymbolV2::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD;
00057 
00058   if ( props.contains( "name" ) )
00059     name = props["name"];
00060   if ( props.contains( "color" ) )
00061     color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
00062   if ( props.contains( "color_border" ) )
00063     borderColor = QgsSymbolLayerV2Utils::decodeColor( props["color_border"] );
00064   if ( props.contains( "size" ) )
00065     size = props["size"].toDouble();
00066   if ( props.contains( "angle" ) )
00067     angle = props["angle"].toDouble();
00068   if ( props.contains( "scale_method" ) )
00069     scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
00070 
00071   QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size, angle, scaleMethod );
00072   if ( props.contains( "offset" ) )
00073     m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
00074   if ( props.contains( "offset_unit" ) )
00075     m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
00076   if ( props.contains( "size_unit" ) )
00077     m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
00078 
00079   if ( props.contains( "outline_width" ) )
00080   {
00081     m->setOutlineWidth( props["outline_width"].toDouble() );
00082   }
00083   if ( props.contains( "outline_width_unit" ) )
00084   {
00085     m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
00086   }
00087 
00088   //data defined properties
00089   if ( props.contains( "name_expression" ) )
00090   {
00091     m->setDataDefinedProperty( "name", props["name_expression"] );
00092   }
00093   if ( props.contains( "color_expression" ) )
00094   {
00095     m->setDataDefinedProperty( "color", props["color_expression"] );
00096   }
00097   if ( props.contains( "color_border_expression" ) )
00098   {
00099     m->setDataDefinedProperty( "color_border", props["color_border_expression"] );
00100   }
00101   if ( props.contains( "outline_width_expression" ) )
00102   {
00103     m->setDataDefinedProperty( "outline_width", props["outline_width_expression"] );
00104   }
00105   if ( props.contains( "size_expression" ) )
00106   {
00107     m->setDataDefinedProperty( "size", props["size_expression"] );
00108   }
00109   if ( props.contains( "angle_expression" ) )
00110   {
00111     m->setDataDefinedProperty( "angle", props["angle_expression"] );
00112   }
00113   if ( props.contains( "offset_expression" ) )
00114   {
00115     m->setDataDefinedProperty( "offset", props["offset_expression"] );
00116   }
00117   return m;
00118 }
00119 
00120 
00121 QString QgsSimpleMarkerSymbolLayerV2::layerType() const
00122 {
00123   return "SimpleMarker";
00124 }
00125 
00126 void QgsSimpleMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
00127 {
00128   QColor brushColor = mColor;
00129   QColor penColor = mBorderColor;
00130 
00131   brushColor.setAlphaF( mColor.alphaF() * context.alpha() );
00132   penColor.setAlphaF( mBorderColor.alphaF() * context.alpha() );
00133 
00134   mBrush = QBrush( brushColor );
00135   mPen = QPen( penColor );
00136   mPen.setWidthF( mOutlineWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOutlineWidthUnit ) );
00137 
00138   QColor selBrushColor = context.renderContext().selectionColor();
00139   QColor selPenColor = selBrushColor == mColor ? selBrushColor : mBorderColor;
00140   if ( context.alpha() < 1 )
00141   {
00142     selBrushColor.setAlphaF( context.alpha() );
00143     selPenColor.setAlphaF( context.alpha() );
00144   }
00145   mSelBrush = QBrush( selBrushColor );
00146   mSelPen = QPen( selPenColor );
00147   mSelPen.setWidthF( mOutlineWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOutlineWidthUnit ) );
00148 
00149   bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || dataDefinedProperty( "angle" );
00150   bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale || dataDefinedProperty( "size" );
00151 
00152   // use caching only when:
00153   // - size, rotation, shape, color, border color is not data-defined
00154   // - drawing to screen (not printer)
00155   mUsingCache = !hasDataDefinedRotation && !hasDataDefinedSize && !context.renderContext().forceVectorOutput()
00156                 && !dataDefinedProperty( "name" ) && !dataDefinedProperty( "color" ) && !dataDefinedProperty( "color_border" ) && !dataDefinedProperty( "outline_width" ) &&
00157                 !dataDefinedProperty( "size" );
00158 
00159   // use either QPolygonF or QPainterPath for drawing
00160   // TODO: find out whether drawing directly doesn't bring overhead - if not, use it for all shapes
00161   if ( !prepareShape() ) // drawing as a polygon
00162   {
00163     if ( preparePath() ) // drawing as a painter path
00164     {
00165       // some markers can't be drawn as a polygon (circle, cross)
00166       // For these set the selected border color to the selected color
00167 
00168       if ( mName != "circle" )
00169         mSelPen.setColor( selBrushColor );
00170     }
00171     else
00172     {
00173       QgsDebugMsg( "unknown symbol" );
00174       return;
00175     }
00176   }
00177 
00178   QMatrix transform;
00179 
00180   // scale the shape (if the size is not going to be modified)
00181   if ( !hasDataDefinedSize )
00182   {
00183     double scaledSize = mSize * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mSizeUnit );
00184     if ( mUsingCache )
00185       scaledSize *= context.renderContext().rasterScaleFactor();
00186     double half = scaledSize / 2.0;
00187     transform.scale( half, half );
00188   }
00189 
00190   // rotate if the rotation is not going to be changed during the rendering
00191   if ( !hasDataDefinedRotation && mAngle != 0 )
00192   {
00193     transform.rotate( mAngle );
00194   }
00195 
00196   if ( !mPolygon.isEmpty() )
00197     mPolygon = transform.map( mPolygon );
00198   else
00199     mPath = transform.map( mPath );
00200 
00201   if ( mUsingCache )
00202   {
00203     prepareCache( context );
00204   }
00205   else
00206   {
00207     mCache = QImage();
00208     mSelCache = QImage();
00209   }
00210 
00211   prepareExpressions( context.layer() );
00212 }
00213 
00214 
00215 void QgsSimpleMarkerSymbolLayerV2::prepareCache( QgsSymbolV2RenderContext& context )
00216 {
00217   double scaledSize = mSize * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mSizeUnit );
00218 
00219   // calculate necessary image size for the cache
00220   double pw = (( mPen.widthF() == 0 ? 1 : mPen.widthF() ) + 1 ) / 2 * 2; // make even (round up); handle cosmetic pen
00221   int imageSize = (( int ) scaledSize + pw ) / 2 * 2 + 1; //  make image width, height odd; account for pen width
00222   double center = imageSize / 2.0;
00223 
00224   mCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
00225   mCache.fill( 0 );
00226 
00227   QPainter p;
00228   p.begin( &mCache );
00229   p.setRenderHint( QPainter::Antialiasing );
00230   p.setBrush( mBrush );
00231   p.setPen( mPen );
00232   p.translate( QPointF( center, center ) );
00233   drawMarker( &p, context );
00234   p.end();
00235 
00236   // Construct the selected version of the Cache
00237 
00238   QColor selColor = context.renderContext().selectionColor();
00239 
00240   mSelCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
00241   mSelCache.fill( 0 );
00242 
00243   p.begin( &mSelCache );
00244   p.setRenderHint( QPainter::Antialiasing );
00245   p.setBrush( mSelBrush );
00246   p.setPen( mSelPen );
00247   p.translate( QPointF( center, center ) );
00248   drawMarker( &p, context );
00249   p.end();
00250 
00251   // Check that the selected version is different.  If not, then re-render,
00252   // filling the background with the selection color and using the normal
00253   // colors for the symbol .. could be ugly!
00254 
00255   if ( mSelCache == mCache )
00256   {
00257     p.begin( &mSelCache );
00258     p.setRenderHint( QPainter::Antialiasing );
00259     p.fillRect( 0, 0, imageSize, imageSize, selColor );
00260     p.setBrush( mBrush );
00261     p.setPen( mPen );
00262     p.translate( QPointF( center, center ) );
00263     drawMarker( &p, context );
00264     p.end();
00265   }
00266 }
00267 
00268 void QgsSimpleMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
00269 {
00270   Q_UNUSED( context );
00271 }
00272 
00273 bool QgsSimpleMarkerSymbolLayerV2::prepareShape( QString name )
00274 {
00275   mPolygon.clear();
00276 
00277   if ( name.isNull() )
00278   {
00279     name = mName;
00280   }
00281 
00282   if ( name == "square" || name == "rectangle" )
00283   {
00284     mPolygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 1, 1 ) ) );
00285     return true;
00286   }
00287   else if ( name == "diamond" )
00288   {
00289     mPolygon << QPointF( -1, 0 ) << QPointF( 0, 1 )
00290     << QPointF( 1, 0 ) << QPointF( 0, -1 );
00291     return true;
00292   }
00293   else if ( name == "pentagon" )
00294   {
00295     mPolygon << QPointF( sin( DEG2RAD( 288.0 ) ), - cos( DEG2RAD( 288.0 ) ) )
00296     << QPointF( sin( DEG2RAD( 216.0 ) ), - cos( DEG2RAD( 216.0 ) ) )
00297     << QPointF( sin( DEG2RAD( 144.0 ) ), - cos( DEG2RAD( 144.0 ) ) )
00298     << QPointF( sin( DEG2RAD( 72.0 ) ), - cos( DEG2RAD( 72.0 ) ) )
00299     << QPointF( 0, -1 );
00300     return true;
00301   }
00302   else if ( name == "triangle" )
00303   {
00304     mPolygon << QPointF( -1, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 );
00305     return true;
00306   }
00307   else if ( name == "equilateral_triangle" )
00308   {
00309     mPolygon << QPointF( sin( DEG2RAD( 240.0 ) ), - cos( DEG2RAD( 240.0 ) ) )
00310     << QPointF( sin( DEG2RAD( 120.0 ) ), - cos( DEG2RAD( 120.0 ) ) )
00311     << QPointF( 0, -1 );
00312     return true;
00313   }
00314   else if ( name == "star" )
00315   {
00316     double sixth = 1.0 / 3;
00317 
00318     mPolygon << QPointF( 0, -1 )
00319     << QPointF( -sixth, -sixth )
00320     << QPointF( -1, -sixth )
00321     << QPointF( -sixth, 0 )
00322     << QPointF( -1, 1 )
00323     << QPointF( 0, + sixth )
00324     << QPointF( 1, 1 )
00325     << QPointF( + sixth, 0 )
00326     << QPointF( 1, -sixth )
00327     << QPointF( + sixth, -sixth );
00328     return true;
00329   }
00330   else if ( name == "regular_star" )
00331   {
00332     double inner_r = cos( DEG2RAD( 72.0 ) ) / cos( DEG2RAD( 36.0 ) );
00333 
00334     mPolygon << QPointF( inner_r * sin( DEG2RAD( 324.0 ) ), - inner_r * cos( DEG2RAD( 324.0 ) ) )  // 324
00335     << QPointF( sin( DEG2RAD( 288.0 ) ) , - cos( DEG2RAD( 288 ) ) )    // 288
00336     << QPointF( inner_r * sin( DEG2RAD( 252.0 ) ), - inner_r * cos( DEG2RAD( 252.0 ) ) )   // 252
00337     << QPointF( sin( DEG2RAD( 216.0 ) ) , - cos( DEG2RAD( 216.0 ) ) )   // 216
00338     << QPointF( 0, inner_r )         // 180
00339     << QPointF( sin( DEG2RAD( 144.0 ) ) , - cos( DEG2RAD( 144.0 ) ) )   // 144
00340     << QPointF( inner_r * sin( DEG2RAD( 108.0 ) ), - inner_r * cos( DEG2RAD( 108.0 ) ) )   // 108
00341     << QPointF( sin( DEG2RAD( 72.0 ) ) , - cos( DEG2RAD( 72.0 ) ) )    //  72
00342     << QPointF( inner_r * sin( DEG2RAD( 36.0 ) ), - inner_r * cos( DEG2RAD( 36.0 ) ) )   //  36
00343     << QPointF( 0, -1 );          //   0
00344     return true;
00345   }
00346   else if ( name == "arrow" )
00347   {
00348     mPolygon
00349     << QPointF( 0, -1 )
00350     << QPointF( 0.5,  -0.5 )
00351     << QPointF( 0.25, -0.25 )
00352     << QPointF( 0.25,  1 )
00353     << QPointF( -0.25,  1 )
00354     << QPointF( -0.25, -0.5 )
00355     << QPointF( -0.5,  -0.5 );
00356     return true;
00357   }
00358   else if ( name == "filled_arrowhead" )
00359   {
00360     mPolygon << QPointF( 0, 0 ) << QPointF( -1, 1 ) << QPointF( -1, -1 );
00361     return true;
00362   }
00363 
00364   return false;
00365 }
00366 
00367 bool QgsSimpleMarkerSymbolLayerV2::preparePath( QString name )
00368 {
00369   mPath = QPainterPath();
00370   if ( name.isNull() )
00371   {
00372     name = mName;
00373   }
00374 
00375   if ( name == "circle" )
00376   {
00377     mPath.addEllipse( QRectF( -1, -1, 2, 2 ) ); // x,y,w,h
00378     return true;
00379   }
00380   else if ( name == "cross" )
00381   {
00382     mPath.moveTo( -1, 0 );
00383     mPath.lineTo( 1, 0 ); // horizontal
00384     mPath.moveTo( 0, -1 );
00385     mPath.lineTo( 0, 1 ); // vertical
00386     return true;
00387   }
00388   else if ( name == "x" || name == "cross2" )
00389   {
00390     mPath.moveTo( -1, -1 );
00391     mPath.lineTo( 1, 1 );
00392     mPath.moveTo( 1, -1 );
00393     mPath.lineTo( -1, 1 );
00394     return true;
00395   }
00396   else if ( name == "line" )
00397   {
00398     mPath.moveTo( 0, -1 );
00399     mPath.lineTo( 0, 1 ); // vertical line
00400     return true;
00401   }
00402   else if ( name == "arrowhead" )
00403   {
00404     mPath.moveTo( 0, 0 );
00405     mPath.lineTo( -1, -1 );
00406     mPath.moveTo( 0, 0 );
00407     mPath.lineTo( -1, 1 );
00408     return true;
00409   }
00410 
00411   return false;
00412 }
00413 
00414 void QgsSimpleMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context )
00415 {
00416   QgsRenderContext& rc = context.renderContext();
00417   QPainter* p = rc.painter();
00418   if ( !p )
00419   {
00420     return;
00421   }
00422 
00423   //offset
00424   double offsetX = 0;
00425   double offsetY = 0;
00426   markerOffset( context, offsetX, offsetY );
00427   QPointF off( offsetX, offsetY );
00428 
00429   //angle
00430   double angle = mAngle;
00431   QgsExpression* angleExpression = expression( "angle" );
00432   if ( angleExpression )
00433   {
00434     angle = angleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
00435   }
00436   if ( angle )
00437     off = _rotatedOffset( off, angle );
00438 
00439   //data defined shape?
00440   QgsExpression* nameExpression = expression( "name" );
00441   if ( nameExpression )
00442   {
00443     QString name = nameExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
00444     if ( !prepareShape( name ) ) // drawing as a polygon
00445     {
00446       preparePath( name ); // drawing as a painter path
00447     }
00448   }
00449 
00450   if ( mUsingCache )
00451   {
00452     // we will use cached image
00453     QImage &img = context.selected() ? mSelCache : mCache;
00454     double s = img.width() / context.renderContext().rasterScaleFactor();
00455     p->drawImage( QRectF( point.x() - s / 2.0 + off.x(),
00456                           point.y() - s / 2.0 + off.y(),
00457                           s, s ), img );
00458   }
00459   else
00460   {
00461     QMatrix transform;
00462 
00463 
00464     bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || angleExpression;
00465     QgsExpression* sizeExpression = expression( "size" );
00466     bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale || sizeExpression;
00467 
00468     // move to the desired position
00469     transform.translate( point.x() + off.x(), point.y() + off.y() );
00470 
00471     // resize if necessary
00472     if ( hasDataDefinedSize )
00473     {
00474       double scaledSize = mSize;
00475       if ( sizeExpression )
00476       {
00477         scaledSize = sizeExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
00478       }
00479       scaledSize *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mSizeUnit );
00480 
00481       switch ( mScaleMethod )
00482       {
00483         case QgsSymbolV2::ScaleArea:
00484           scaledSize = sqrt( scaledSize );
00485           break;
00486         case QgsSymbolV2::ScaleDiameter:
00487           break;
00488       }
00489 
00490       double half = scaledSize / 2.0;
00491       transform.scale( half, half );
00492     }
00493 
00494     // rotate if necessary
00495     if ( angle != 0 && hasDataDefinedRotation )
00496     {
00497       transform.rotate( angle );
00498     }
00499 
00500     QgsExpression* colorExpression = expression( "color" );
00501     QgsExpression* colorBorderExpression = expression( "color_border" );
00502     QgsExpression* outlineWidthExpression = expression( "outline_width" );
00503     if ( colorExpression )
00504     {
00505       mBrush.setColor( QgsSymbolLayerV2Utils::decodeColor( colorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
00506     }
00507     if ( colorBorderExpression )
00508     {
00509       mPen.setColor( QgsSymbolLayerV2Utils::decodeColor( colorBorderExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
00510       mSelPen.setColor( QgsSymbolLayerV2Utils::decodeColor( colorBorderExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
00511     }
00512     if ( outlineWidthExpression )
00513     {
00514       double outlineWidth = outlineWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
00515       mPen.setWidthF( outlineWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOutlineWidthUnit ) );
00516       mSelPen.setWidthF( outlineWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOutlineWidthUnit ) );
00517     }
00518 
00519     p->setBrush( context.selected() ? mSelBrush : mBrush );
00520     p->setPen( context.selected() ? mSelPen : mPen );
00521 
00522     if ( !mPolygon.isEmpty() )
00523       p->drawPolygon( transform.map( mPolygon ) );
00524     else
00525       p->drawPath( transform.map( mPath ) );
00526   }
00527 }
00528 
00529 
00530 QgsStringMap QgsSimpleMarkerSymbolLayerV2::properties() const
00531 {
00532   QgsStringMap map;
00533   map["name"] = mName;
00534   map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
00535   map["color_border"] = QgsSymbolLayerV2Utils::encodeColor( mBorderColor );
00536   map["size"] = QString::number( mSize );
00537   map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
00538   map["angle"] = QString::number( mAngle );
00539   map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
00540   map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
00541   map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
00542   map["outline_width"] = QString::number( mOutlineWidth );
00543   map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
00544 
00545   //data define properties
00546   saveDataDefinedProperties( map );
00547   return map;
00548 }
00549 
00550 QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::clone() const
00551 {
00552   QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( mName, mColor, mBorderColor, mSize, mAngle, mScaleMethod );
00553   m->setOffset( mOffset );
00554   m->setSizeUnit( mSizeUnit );
00555   m->setOffsetUnit( mOffsetUnit );
00556   m->setOutlineWidth( mOutlineWidth );
00557   m->setOutlineWidthUnit( mOutlineWidthUnit );
00558   copyDataDefinedProperties( m );
00559   return m;
00560 }
00561 
00562 void QgsSimpleMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
00563 {
00564   // <Graphic>
00565   QDomElement graphicElem = doc.createElement( "se:Graphic" );
00566   element.appendChild( graphicElem );
00567 
00568   QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, mName, mColor, mBorderColor, -1, mSize );
00569 
00570   // <Rotation>
00571   QString angleFunc;
00572   bool ok;
00573   double angle = props.value( "angle", "0" ).toDouble( &ok );
00574   if ( !ok )
00575   {
00576     angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
00577   }
00578   else if ( angle + mAngle != 0 )
00579   {
00580     angleFunc = QString::number( angle + mAngle );
00581   }
00582   QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
00583 
00584   // <Displacement>
00585   QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
00586 }
00587 
00588 QString QgsSimpleMarkerSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
00589 {
00590   Q_UNUSED( mmScaleFactor );
00591   Q_UNUSED( mapUnitScaleFactor );
00592 #if 0
00593   QString ogrType = "3"; //default is circle
00594   if ( mName == "square" )
00595   {
00596     ogrType = "5";
00597   }
00598   else if ( mName == "triangle" )
00599   {
00600     ogrType = "7";
00601   }
00602   else if ( mName == "star" )
00603   {
00604     ogrType = "9";
00605   }
00606   else if ( mName == "circle" )
00607   {
00608     ogrType = "3";
00609   }
00610   else if ( mName == "cross" )
00611   {
00612     ogrType = "0";
00613   }
00614   else if ( mName == "x" || mName == "cross2" )
00615   {
00616     ogrType = "1";
00617   }
00618   else if ( mName == "line" )
00619   {
00620     ogrType = "10";
00621   }
00622 
00623   QString ogrString;
00624   ogrString.append( "SYMBOL(" );
00625   ogrString.append( "id:" );
00626   ogrString.append( "\"" );
00627   ogrString.append( "ogr-sym-" );
00628   ogrString.append( ogrType );
00629   ogrString.append( "\"" );
00630   ogrString.append( ",c:" );
00631   ogrString.append( mColor.name() );
00632   ogrString.append( ",o:" );
00633   ogrString.append( mBorderColor.name() );
00634   ogrString.append( QString( ",s:%1mm" ).arg( mSize ) );
00635   ogrString.append( ")" );
00636   return ogrString;
00637 #endif //0
00638 
00639   QString ogrString;
00640   ogrString.append( "PEN(" );
00641   ogrString.append( "c:" );
00642   ogrString.append( mColor.name() );
00643   ogrString.append( ",w:" );
00644   ogrString.append( QString::number( mSize ) );
00645   ogrString.append( "mm" );
00646   ogrString.append( ")" );
00647   return ogrString;
00648 }
00649 
00650 QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::createFromSld( QDomElement &element )
00651 {
00652   QgsDebugMsg( "Entered." );
00653 
00654   QDomElement graphicElem = element.firstChildElement( "Graphic" );
00655   if ( graphicElem.isNull() )
00656     return NULL;
00657 
00658   QString name = "square";
00659   QColor color, borderColor;
00660   double borderWidth, size;
00661 
00662   if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, color, borderColor, borderWidth, size ) )
00663     return NULL;
00664 
00665   double angle = 0.0;
00666   QString angleFunc;
00667   if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
00668   {
00669     bool ok;
00670     double d = angleFunc.toDouble( &ok );
00671     if ( ok )
00672       angle = d;
00673   }
00674 
00675   QPointF offset;
00676   QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );
00677 
00678   QgsMarkerSymbolLayerV2 *m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size );
00679   m->setAngle( angle );
00680   m->setOffset( offset );
00681   return m;
00682 }
00683 
00684 void QgsSimpleMarkerSymbolLayerV2::drawMarker( QPainter* p, QgsSymbolV2RenderContext& context )
00685 {
00686   Q_UNUSED( context );
00687 
00688   if ( mPolygon.count() != 0 )
00689   {
00690     p->drawPolygon( mPolygon );
00691   }
00692   else
00693   {
00694     p->drawPath( mPath );
00695   }
00696 }
00697 
00699 
00700 
00701 QgsSvgMarkerSymbolLayerV2::QgsSvgMarkerSymbolLayerV2( QString name, double size, double angle )
00702 {
00703   mPath = QgsSymbolLayerV2Utils::symbolNameToPath( name );
00704   mSize = size;
00705   mAngle = angle;
00706   mOffset = QPointF( 0, 0 );
00707   mOutlineWidth = 1.0;
00708   mOutlineWidthUnit = QgsSymbolV2::MM;
00709   mFillColor = QColor( Qt::black );
00710   mOutlineColor = QColor( Qt::black );
00711 }
00712 
00713 
00714 QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::create( const QgsStringMap& props )
00715 {
00716   QString name = DEFAULT_SVGMARKER_NAME;
00717   double size = DEFAULT_SVGMARKER_SIZE;
00718   double angle = DEFAULT_SVGMARKER_ANGLE;
00719 
00720   if ( props.contains( "name" ) )
00721     name = props["name"];
00722   if ( props.contains( "size" ) )
00723     size = props["size"].toDouble();
00724   if ( props.contains( "angle" ) )
00725     angle = props["angle"].toDouble();
00726 
00727   QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle );
00728 
00729   //we only check the svg default parameters if necessary, since it could be expensive
00730   if ( !props.contains( "fill" ) && !props.contains( "outline" ) && !props.contains( "outline-width" ) )
00731   {
00732     QColor fillColor, outlineColor;
00733     double outlineWidth;
00734     bool hasFillParam, hasOutlineParam, hasOutlineWidthParam;
00735     QgsSvgCache::instance()->containsParams( name, hasFillParam, fillColor, hasOutlineParam, outlineColor, hasOutlineWidthParam, outlineWidth );
00736     if ( hasFillParam )
00737     {
00738       m->setFillColor( fillColor );
00739     }
00740     if ( hasOutlineParam )
00741     {
00742       m->setOutlineColor( outlineColor );
00743     }
00744     if ( hasOutlineWidthParam )
00745     {
00746       m->setOutlineWidth( outlineWidth );
00747     }
00748   }
00749 
00750   if ( props.contains( "size_unit" ) )
00751     m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
00752   if ( props.contains( "offset" ) )
00753     m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
00754   if ( props.contains( "offset_unit" ) )
00755     m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
00756   if ( props.contains( "fill" ) )
00757     m->setFillColor( QColor( props["fill"] ) );
00758   if ( props.contains( "outline" ) )
00759     m->setOutlineColor( QColor( props["outline"] ) );
00760   if ( props.contains( "outline-width" ) )
00761     m->setOutlineWidth( props["outline-width"].toDouble() );
00762   if ( props.contains( "outline_width_unit" ) )
00763     m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
00764 
00765   //data defined properties
00766   if ( props.contains( "size_expression" ) )
00767   {
00768     m->setDataDefinedProperty( "size", props["size_expression"] );
00769   }
00770   if ( props.contains( "outline-width_expression" ) )
00771   {
00772     m->setDataDefinedProperty( "outline-width", props["outline-width_expression"] );
00773   }
00774   if ( props.contains( "angle_expression" ) )
00775   {
00776     m->setDataDefinedProperty( "angle", props["angle_expression"] );
00777   }
00778   if ( props.contains( "offset_expression" ) )
00779   {
00780     m->setDataDefinedProperty( "offset", props["offset_expression"] );
00781   }
00782   if ( props.contains( "name_expression" ) )
00783   {
00784     m->setDataDefinedProperty( "name", props["name_expression"] );
00785   }
00786   if ( props.contains( "fill_expression" ) )
00787   {
00788     m->setDataDefinedProperty( "fill", props["fill_expression"] );
00789   }
00790   if ( props.contains( "outline_expression" ) )
00791   {
00792     m->setDataDefinedProperty( "outline", props["outline_expression"] );
00793   }
00794   return m;
00795 }
00796 
00797 void QgsSvgMarkerSymbolLayerV2::setPath( QString path )
00798 {
00799   mPath = path;
00800   QColor fillColor, outlineColor;
00801   double outlineWidth;
00802   bool hasFillParam, hasOutlineParam, hasOutlineWidthParam;
00803   QgsSvgCache::instance()->containsParams( path, hasFillParam, fillColor, hasOutlineParam, outlineColor, hasOutlineWidthParam, outlineWidth );
00804   if ( hasFillParam )
00805   {
00806     setFillColor( fillColor );
00807   }
00808   if ( hasOutlineParam )
00809   {
00810     setOutlineColor( outlineColor );
00811   }
00812   if ( hasOutlineWidthParam )
00813   {
00814     setOutlineWidth( outlineWidth );
00815   }
00816 }
00817 
00818 
00819 QString QgsSvgMarkerSymbolLayerV2::layerType() const
00820 {
00821   return "SvgMarker";
00822 }
00823 
00824 void QgsSvgMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
00825 {
00826   mOrigSize = mSize; // save in case the size would be data defined
00827   Q_UNUSED( context );
00828   prepareExpressions( context.layer() );
00829 }
00830 
00831 void QgsSvgMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
00832 {
00833   Q_UNUSED( context );
00834 }
00835 
00836 void QgsSvgMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context )
00837 {
00838   QPainter* p = context.renderContext().painter();
00839   if ( !p )
00840   {
00841     return;
00842   }
00843 
00844   double size = mSize;
00845   QgsExpression* sizeExpression = expression( "size" );
00846   bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale || sizeExpression;
00847 
00848   if ( sizeExpression )
00849   {
00850     size = sizeExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
00851   }
00852   size *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mSizeUnit );
00853 
00854   if ( hasDataDefinedSize )
00855   {
00856     switch ( mScaleMethod )
00857     {
00858       case QgsSymbolV2::ScaleArea:
00859         size = sqrt( size );
00860         break;
00861       case QgsSymbolV2::ScaleDiameter:
00862         break;
00863     }
00864   }
00865 
00866   //don't render symbols with size below one or above 10,000 pixels
00867   if (( int )size < 1 || 10000.0 < size )
00868   {
00869     return;
00870   }
00871 
00872   p->save();
00873 
00874   QPointF offset = mOffset;
00875   QgsExpression* offsetExpression = expression( "offset" );
00876   if ( offsetExpression )
00877   {
00878     QString offsetString =  offsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
00879     offset = QgsSymbolLayerV2Utils::decodePoint( offsetString );
00880   }
00881   double offsetX = offset.x() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
00882   double offsetY = offset.y() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
00883   QPointF outputOffset( offsetX, offsetY );
00884 
00885   double angle = mAngle;
00886   QgsExpression* angleExpression = expression( "angle" );
00887   if ( angleExpression )
00888   {
00889     angle = angleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
00890   }
00891   if ( angle )
00892     outputOffset = _rotatedOffset( outputOffset, angle );
00893   p->translate( point + outputOffset );
00894 
00895   bool rotated = !qgsDoubleNear( angle, 0 );
00896   bool drawOnScreen = qgsDoubleNear( context.renderContext().rasterScaleFactor(), 1.0, 0.1 );
00897   if ( rotated )
00898     p->rotate( angle );
00899 
00900   QString path = mPath;
00901   QgsExpression* nameExpression = expression( "name" );
00902   if ( nameExpression )
00903   {
00904     path = nameExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
00905   }
00906 
00907   double outlineWidth = mOutlineWidth;
00908   QgsExpression* outlineWidthExpression = expression( "outline_width" );
00909   if ( outlineWidthExpression )
00910   {
00911     outlineWidth = outlineWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
00912   }
00913 
00914   QColor fillColor = mFillColor;
00915   QgsExpression* fillExpression = expression( "fill" );
00916   if ( fillExpression )
00917   {
00918     fillColor = QgsSymbolLayerV2Utils::decodeColor( fillExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
00919   }
00920 
00921   QColor outlineColor = mOutlineColor;
00922   QgsExpression* outlineExpression = expression( "outline" );
00923   if ( outlineExpression )
00924   {
00925     outlineColor = QgsSymbolLayerV2Utils::decodeColor( outlineExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
00926   }
00927 
00928 
00929   bool fitsInCache = true;
00930   bool usePict = true;
00931   double hwRatio = 1.0;
00932   if ( drawOnScreen && !rotated )
00933   {
00934     usePict = false;
00935     const QImage& img = QgsSvgCache::instance()->svgAsImage( path, size, fillColor, outlineColor, outlineWidth,
00936                         context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
00937     if ( fitsInCache && img.width() > 1 )
00938     {
00939       //consider transparency
00940       if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
00941       {
00942         QImage transparentImage = img.copy();
00943         QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
00944         p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
00945         hwRatio = ( double )transparentImage.height() / ( double )transparentImage.width();
00946       }
00947       else
00948       {
00949         p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
00950         hwRatio = ( double )img.height() / ( double )img.width();
00951       }
00952     }
00953   }
00954 
00955   if ( usePict || !fitsInCache )
00956   {
00957     p->setOpacity( context.alpha() );
00958     const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( path, size, fillColor, outlineColor, outlineWidth,
00959                           context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() );
00960 
00961     if ( pct.width() > 1 )
00962     {
00963       p->drawPicture( 0, 0, pct );
00964       hwRatio = ( double )pct.height() / ( double )pct.width();
00965     }
00966   }
00967 
00968   if ( context.selected() )
00969   {
00970     QPen pen( context.renderContext().selectionColor() );
00971     double penWidth = QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), QgsSymbolV2::MM );
00972     if ( penWidth > size / 20 )
00973     {
00974       // keep the pen width from covering symbol
00975       penWidth = size / 20;
00976     }
00977     double penOffset = penWidth / 2;
00978     pen.setWidth( penWidth );
00979     p->setPen( pen );
00980     p->setBrush( Qt::NoBrush );
00981     double wSize = size + penOffset;
00982     double hSize = size * hwRatio + penOffset;
00983     p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) );
00984   }
00985 
00986   p->restore();
00987 }
00988 
00989 
00990 QgsStringMap QgsSvgMarkerSymbolLayerV2::properties() const
00991 {
00992   QgsStringMap map;
00993   map["name"] = QgsSymbolLayerV2Utils::symbolPathToName( mPath );
00994   map["size"] = QString::number( mSize );
00995   map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
00996   map["angle"] = QString::number( mAngle );
00997   map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
00998   map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
00999   map["fill"] = mFillColor.name();
01000   map["outline"] = mOutlineColor.name();
01001   map["outline-width"] = QString::number( mOutlineWidth );
01002   map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
01003   saveDataDefinedProperties( map );
01004   return map;
01005 }
01006 
01007 QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::clone() const
01008 {
01009   QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( mPath, mSize, mAngle );
01010   m->setFillColor( mFillColor );
01011   m->setOutlineColor( mOutlineColor );
01012   m->setOutlineWidth( mOutlineWidth );
01013   m->setOutlineWidthUnit( mOutlineWidthUnit );
01014   m->setOffset( mOffset );
01015   m->setOffsetUnit( mOffsetUnit );
01016   m->setSizeUnit( mSizeUnit );
01017   copyDataDefinedProperties( m );
01018   return m;
01019 }
01020 
01021 void QgsSvgMarkerSymbolLayerV2::setOutputUnit( QgsSymbolV2::OutputUnit unit )
01022 {
01023   mSizeUnit = unit;
01024   mOffsetUnit = unit;
01025   mOutlineWidthUnit = unit;
01026 }
01027 
01028 QgsSymbolV2::OutputUnit QgsSvgMarkerSymbolLayerV2::outputUnit() const
01029 {
01030   QgsSymbolV2::OutputUnit unit = mSizeUnit;
01031   if ( unit != mOffsetUnit || unit != mOutlineWidthUnit )
01032   {
01033     return QgsSymbolV2::Mixed;
01034   }
01035   return unit;
01036 }
01037 
01038 void QgsSvgMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
01039 {
01040   // <Graphic>
01041   QDomElement graphicElem = doc.createElement( "se:Graphic" );
01042   element.appendChild( graphicElem );
01043 
01044   QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mFillColor, mSize );
01045 
01046   // <Rotation>
01047   QString angleFunc;
01048   bool ok;
01049   double angle = props.value( "angle", "0" ).toDouble( &ok );
01050   if ( !ok )
01051   {
01052     angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
01053   }
01054   else if ( angle + mAngle != 0 )
01055   {
01056     angleFunc = QString::number( angle + mAngle );
01057   }
01058 
01059   QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
01060 
01061   // <Displacement>
01062   QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
01063 }
01064 
01065 QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::createFromSld( QDomElement &element )
01066 {
01067   QgsDebugMsg( "Entered." );
01068 
01069   QDomElement graphicElem = element.firstChildElement( "Graphic" );
01070   if ( graphicElem.isNull() )
01071     return NULL;
01072 
01073   QString path, mimeType;
01074   QColor fillColor;
01075   double size;
01076 
01077   if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
01078     return NULL;
01079 
01080   if ( mimeType != "image/svg+xml" )
01081     return NULL;
01082 
01083   double angle = 0.0;
01084   QString angleFunc;
01085   if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
01086   {
01087     bool ok;
01088     double d = angleFunc.toDouble( &ok );
01089     if ( ok )
01090       angle = d;
01091   }
01092 
01093   QPointF offset;
01094   QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );
01095 
01096   QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( path, size );
01097   m->setFillColor( fillColor );
01098   //m->setOutlineColor( outlineColor );
01099   //m->setOutlineWidth( outlineWidth );
01100   m->setAngle( angle );
01101   m->setOffset( offset );
01102   return m;
01103 }
01104 
01106 
01107 QgsFontMarkerSymbolLayerV2::QgsFontMarkerSymbolLayerV2( QString fontFamily, QChar chr, double pointSize, QColor color, double angle )
01108 {
01109   mFontFamily = fontFamily;
01110   mChr = chr;
01111   mColor = color;
01112   mAngle = angle;
01113   mSize = pointSize;
01114   mSizeUnit = QgsSymbolV2::MM;
01115   mOffset = QPointF( 0, 0 );
01116   mOffsetUnit = QgsSymbolV2::MM;
01117 }
01118 
01119 QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::create( const QgsStringMap& props )
01120 {
01121   QString fontFamily = DEFAULT_FONTMARKER_FONT;
01122   QChar chr = DEFAULT_FONTMARKER_CHR;
01123   double pointSize = DEFAULT_FONTMARKER_SIZE;
01124   QColor color = DEFAULT_FONTMARKER_COLOR;
01125   double angle = DEFAULT_FONTMARKER_ANGLE;
01126 
01127   if ( props.contains( "font" ) )
01128     fontFamily = props["font"];
01129   if ( props.contains( "chr" ) && props["chr"].length() > 0 )
01130     chr = props["chr"].at( 0 );
01131   if ( props.contains( "size" ) )
01132     pointSize = props["size"].toDouble();
01133   if ( props.contains( "color" ) )
01134     color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
01135   if ( props.contains( "angle" ) )
01136     angle = props["angle"].toDouble();
01137 
01138   QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, pointSize, color, angle );
01139   if ( props.contains( "offset" ) )
01140     m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
01141   if ( props.contains( "offset_unit" ) )
01142     m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit" ] ) );
01143   if ( props.contains( "size_unit" ) )
01144     m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
01145   return m;
01146 }
01147 
01148 QString QgsFontMarkerSymbolLayerV2::layerType() const
01149 {
01150   return "FontMarker";
01151 }
01152 
01153 void QgsFontMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
01154 {
01155   mFont = QFont( mFontFamily );
01156   mFont.setPixelSize( mSize * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mSizeUnit ) );
01157   QFontMetrics fm( mFont );
01158   mChrOffset = QPointF( fm.width( mChr ) / 2, -fm.ascent() / 2 );
01159 
01160   mOrigSize = mSize; // save in case the size would be data defined
01161 }
01162 
01163 void QgsFontMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
01164 {
01165   Q_UNUSED( context );
01166 }
01167 
01168 void QgsFontMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context )
01169 {
01170   QPainter* p = context.renderContext().painter();
01171   QColor penColor = context.selected() ? context.renderContext().selectionColor() : mColor;
01172   penColor.setAlphaF( mColor.alphaF() * context.alpha() );
01173   p->setPen( penColor );
01174   p->setFont( mFont );
01175 
01176 
01177   p->save();
01178   double offsetX = mOffset.x() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
01179   double offsetY = mOffset.y() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
01180   QPointF outputOffset( offsetX, offsetY );
01181   if ( mAngle )
01182     outputOffset = _rotatedOffset( outputOffset, mAngle );
01183   p->translate( point + outputOffset );
01184 
01185   if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
01186   {
01187     double s = mSize / mOrigSize;
01188     p->scale( s, s );
01189   }
01190 
01191   if ( mAngle != 0 )
01192     p->rotate( mAngle );
01193 
01194   p->drawText( -mChrOffset, mChr );
01195   p->restore();
01196 }
01197 
01198 QgsStringMap QgsFontMarkerSymbolLayerV2::properties() const
01199 {
01200   QgsStringMap props;
01201   props["font"] = mFontFamily;
01202   props["chr"] = mChr;
01203   props["size"] = QString::number( mSize );
01204   props["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
01205   props["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
01206   props["angle"] = QString::number( mAngle );
01207   props["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
01208   props["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
01209   return props;
01210 }
01211 
01212 QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::clone() const
01213 {
01214   QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( mFontFamily, mChr, mSize, mColor, mAngle );
01215   m->setOffset( mOffset );
01216   m->setOffsetUnit( mOffsetUnit );
01217   m->setSizeUnit( mSizeUnit );
01218   return m;
01219 }
01220 
01221 void QgsFontMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
01222 {
01223   // <Graphic>
01224   QDomElement graphicElem = doc.createElement( "se:Graphic" );
01225   element.appendChild( graphicElem );
01226 
01227   QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
01228   int markIndex = mChr.unicode();
01229   QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, mSize );
01230 
01231   // <Rotation>
01232   QString angleFunc;
01233   bool ok;
01234   double angle = props.value( "angle", "0" ).toDouble( &ok );
01235   if ( !ok )
01236   {
01237     angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
01238   }
01239   else if ( angle + mAngle != 0 )
01240   {
01241     angleFunc = QString::number( angle + mAngle );
01242   }
01243   QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
01244 
01245   // <Displacement>
01246   QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
01247 }
01248 
01249 QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::createFromSld( QDomElement &element )
01250 {
01251   QgsDebugMsg( "Entered." );
01252 
01253   QDomElement graphicElem = element.firstChildElement( "Graphic" );
01254   if ( graphicElem.isNull() )
01255     return NULL;
01256 
01257   QString name, format;
01258   QColor color;
01259   double size;
01260   int chr;
01261 
01262   if ( !QgsSymbolLayerV2Utils::externalMarkerFromSld( graphicElem, name, format, chr, color, size ) )
01263     return NULL;
01264 
01265   if ( !name.startsWith( "ttf://" ) || format != "ttf" )
01266     return NULL;
01267 
01268   QString fontFamily = name.mid( 6 );
01269 
01270   double angle = 0.0;
01271   QString angleFunc;
01272   if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
01273   {
01274     bool ok;
01275     double d = angleFunc.toDouble( &ok );
01276     if ( ok )
01277       angle = d;
01278   }
01279 
01280   QPointF offset;
01281   QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );
01282 
01283   QgsMarkerSymbolLayerV2 *m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, size, color );
01284   m->setAngle( angle );
01285   m->setOffset( offset );
01286   return m;
01287 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines