Quantum GIS API Documentation  master-693a1fe
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   if ( sizeExpression )
00847   {
00848     size = sizeExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
00849   }
00850   size *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mSizeUnit );
00851   //don't render symbols with size below one or above 10,000 pixels
00852   if (( int )size < 1 || 10000.0 < size )
00853   {
00854     return;
00855   }
00856 
00857   p->save();
00858 
00859   QPointF offset = mOffset;
00860   QgsExpression* offsetExpression = expression( "offset" );
00861   if ( offsetExpression )
00862   {
00863     QString offsetString =  offsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
00864     offset = QgsSymbolLayerV2Utils::decodePoint( offsetString );
00865   }
00866   double offsetX = offset.x() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
00867   double offsetY = offset.y() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
00868   QPointF outputOffset( offsetX, offsetY );
00869 
00870   double angle = mAngle;
00871   QgsExpression* angleExpression = expression( "angle" );
00872   if ( angleExpression )
00873   {
00874     angle = angleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
00875   }
00876   if ( angle )
00877     outputOffset = _rotatedOffset( outputOffset, angle );
00878   p->translate( point + outputOffset );
00879 
00880   bool rotated = !qgsDoubleNear( angle, 0 );
00881   bool drawOnScreen = qgsDoubleNear( context.renderContext().rasterScaleFactor(), 1.0, 0.1 );
00882   if ( rotated )
00883     p->rotate( angle );
00884 
00885   QString path = mPath;
00886   QgsExpression* nameExpression = expression( "name" );
00887   if ( nameExpression )
00888   {
00889     path = nameExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
00890   }
00891 
00892   double outlineWidth = mOutlineWidth;
00893   QgsExpression* outlineWidthExpression = expression( "outline_width" );
00894   if ( outlineWidthExpression )
00895   {
00896     outlineWidth = outlineWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
00897   }
00898 
00899   QColor fillColor = mFillColor;
00900   QgsExpression* fillExpression = expression( "fill" );
00901   if ( fillExpression )
00902   {
00903     fillColor = QgsSymbolLayerV2Utils::decodeColor( fillExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
00904   }
00905 
00906   QColor outlineColor = mOutlineColor;
00907   QgsExpression* outlineExpression = expression( "outline" );
00908   if ( outlineExpression )
00909   {
00910     outlineColor = QgsSymbolLayerV2Utils::decodeColor( outlineExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
00911   }
00912 
00913 
00914   bool fitsInCache = true;
00915   bool usePict = true;
00916   double hwRatio = 1.0;
00917   if ( drawOnScreen && !rotated )
00918   {
00919     usePict = false;
00920     const QImage& img = QgsSvgCache::instance()->svgAsImage( path, size, fillColor, outlineColor, outlineWidth,
00921                         context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
00922     if ( fitsInCache && img.width() > 1 )
00923     {
00924       //consider transparency
00925       if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
00926       {
00927         QImage transparentImage = img.copy();
00928         QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
00929         p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
00930         hwRatio = ( double )transparentImage.height() / ( double )transparentImage.width();
00931       }
00932       else
00933       {
00934         p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
00935         hwRatio = ( double )img.height() / ( double )img.width();
00936       }
00937     }
00938   }
00939 
00940   if ( usePict || !fitsInCache )
00941   {
00942     p->setOpacity( context.alpha() );
00943     const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( path, size, fillColor, outlineColor, outlineWidth,
00944                           context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() );
00945 
00946     if ( pct.width() > 1 )
00947     {
00948       p->drawPicture( 0, 0, pct );
00949       hwRatio = ( double )pct.height() / ( double )pct.width();
00950     }
00951   }
00952 
00953   if ( context.selected() )
00954   {
00955     QPen pen( context.renderContext().selectionColor() );
00956     double penWidth = QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), QgsSymbolV2::MM );
00957     if ( penWidth > size / 20 )
00958     {
00959       // keep the pen width from covering symbol
00960       penWidth = size / 20;
00961     }
00962     double penOffset = penWidth / 2;
00963     pen.setWidth( penWidth );
00964     p->setPen( pen );
00965     p->setBrush( Qt::NoBrush );
00966     double wSize = size + penOffset;
00967     double hSize = size * hwRatio + penOffset;
00968     p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) );
00969   }
00970 
00971   p->restore();
00972 }
00973 
00974 
00975 QgsStringMap QgsSvgMarkerSymbolLayerV2::properties() const
00976 {
00977   QgsStringMap map;
00978   map["name"] = QgsSymbolLayerV2Utils::symbolPathToName( mPath );
00979   map["size"] = QString::number( mSize );
00980   map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
00981   map["angle"] = QString::number( mAngle );
00982   map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
00983   map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
00984   map["fill"] = mFillColor.name();
00985   map["outline"] = mOutlineColor.name();
00986   map["outline-width"] = QString::number( mOutlineWidth );
00987   map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
00988   saveDataDefinedProperties( map );
00989   return map;
00990 }
00991 
00992 QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::clone() const
00993 {
00994   QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( mPath, mSize, mAngle );
00995   m->setFillColor( mFillColor );
00996   m->setOutlineColor( mOutlineColor );
00997   m->setOutlineWidth( mOutlineWidth );
00998   m->setOutlineWidthUnit( mOutlineWidthUnit );
00999   m->setOffset( mOffset );
01000   m->setOffsetUnit( mOffsetUnit );
01001   m->setSizeUnit( mSizeUnit );
01002   copyDataDefinedProperties( m );
01003   return m;
01004 }
01005 
01006 void QgsSvgMarkerSymbolLayerV2::setOutputUnit( QgsSymbolV2::OutputUnit unit )
01007 {
01008   mSizeUnit = unit;
01009   mOffsetUnit = unit;
01010   mOutlineWidthUnit = unit;
01011 }
01012 
01013 QgsSymbolV2::OutputUnit QgsSvgMarkerSymbolLayerV2::outputUnit() const
01014 {
01015   QgsSymbolV2::OutputUnit unit = mSizeUnit;
01016   if ( unit != mOffsetUnit || unit != mOutlineWidthUnit )
01017   {
01018     return QgsSymbolV2::Mixed;
01019   }
01020   return unit;
01021 }
01022 
01023 void QgsSvgMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
01024 {
01025   // <Graphic>
01026   QDomElement graphicElem = doc.createElement( "se:Graphic" );
01027   element.appendChild( graphicElem );
01028 
01029   QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mFillColor, mSize );
01030 
01031   // <Rotation>
01032   QString angleFunc;
01033   bool ok;
01034   double angle = props.value( "angle", "0" ).toDouble( &ok );
01035   if ( !ok )
01036   {
01037     angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
01038   }
01039   else if ( angle + mAngle != 0 )
01040   {
01041     angleFunc = QString::number( angle + mAngle );
01042   }
01043 
01044   QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
01045 
01046   // <Displacement>
01047   QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
01048 }
01049 
01050 QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::createFromSld( QDomElement &element )
01051 {
01052   QgsDebugMsg( "Entered." );
01053 
01054   QDomElement graphicElem = element.firstChildElement( "Graphic" );
01055   if ( graphicElem.isNull() )
01056     return NULL;
01057 
01058   QString path, mimeType;
01059   QColor fillColor;
01060   double size;
01061 
01062   if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
01063     return NULL;
01064 
01065   if ( mimeType != "image/svg+xml" )
01066     return NULL;
01067 
01068   double angle = 0.0;
01069   QString angleFunc;
01070   if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
01071   {
01072     bool ok;
01073     double d = angleFunc.toDouble( &ok );
01074     if ( ok )
01075       angle = d;
01076   }
01077 
01078   QPointF offset;
01079   QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );
01080 
01081   QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( path, size );
01082   m->setFillColor( fillColor );
01083   //m->setOutlineColor( outlineColor );
01084   //m->setOutlineWidth( outlineWidth );
01085   m->setAngle( angle );
01086   m->setOffset( offset );
01087   return m;
01088 }
01089 
01091 
01092 QgsFontMarkerSymbolLayerV2::QgsFontMarkerSymbolLayerV2( QString fontFamily, QChar chr, double pointSize, QColor color, double angle )
01093 {
01094   mFontFamily = fontFamily;
01095   mChr = chr;
01096   mColor = color;
01097   mAngle = angle;
01098   mSize = pointSize;
01099   mSizeUnit = QgsSymbolV2::MM;
01100   mOffset = QPointF( 0, 0 );
01101   mOffsetUnit = QgsSymbolV2::MM;
01102 }
01103 
01104 QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::create( const QgsStringMap& props )
01105 {
01106   QString fontFamily = DEFAULT_FONTMARKER_FONT;
01107   QChar chr = DEFAULT_FONTMARKER_CHR;
01108   double pointSize = DEFAULT_FONTMARKER_SIZE;
01109   QColor color = DEFAULT_FONTMARKER_COLOR;
01110   double angle = DEFAULT_FONTMARKER_ANGLE;
01111 
01112   if ( props.contains( "font" ) )
01113     fontFamily = props["font"];
01114   if ( props.contains( "chr" ) && props["chr"].length() > 0 )
01115     chr = props["chr"].at( 0 );
01116   if ( props.contains( "size" ) )
01117     pointSize = props["size"].toDouble();
01118   if ( props.contains( "color" ) )
01119     color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
01120   if ( props.contains( "angle" ) )
01121     angle = props["angle"].toDouble();
01122 
01123   QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, pointSize, color, angle );
01124   if ( props.contains( "offset" ) )
01125     m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
01126   if ( props.contains( "offset_unit" ) )
01127     m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit" ] ) );
01128   if ( props.contains( "size_unit" ) )
01129     m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
01130   return m;
01131 }
01132 
01133 QString QgsFontMarkerSymbolLayerV2::layerType() const
01134 {
01135   return "FontMarker";
01136 }
01137 
01138 void QgsFontMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
01139 {
01140   mFont = QFont( mFontFamily );
01141   mFont.setPixelSize( mSize * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mSizeUnit ) );
01142   QFontMetrics fm( mFont );
01143   mChrOffset = QPointF( fm.width( mChr ) / 2, -fm.ascent() / 2 );
01144 
01145   mOrigSize = mSize; // save in case the size would be data defined
01146 }
01147 
01148 void QgsFontMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
01149 {
01150   Q_UNUSED( context );
01151 }
01152 
01153 void QgsFontMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context )
01154 {
01155   QPainter* p = context.renderContext().painter();
01156   QColor penColor = context.selected() ? context.renderContext().selectionColor() : mColor;
01157   penColor.setAlphaF( mColor.alphaF() * context.alpha() );
01158   p->setPen( penColor );
01159   p->setFont( mFont );
01160 
01161 
01162   p->save();
01163   double offsetX = mOffset.x() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
01164   double offsetY = mOffset.y() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
01165   QPointF outputOffset( offsetX, offsetY );
01166   if ( mAngle )
01167     outputOffset = _rotatedOffset( outputOffset, mAngle );
01168   p->translate( point + outputOffset );
01169 
01170   if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
01171   {
01172     double s = mSize / mOrigSize;
01173     p->scale( s, s );
01174   }
01175 
01176   if ( mAngle != 0 )
01177     p->rotate( mAngle );
01178 
01179   p->drawText( -mChrOffset, mChr );
01180   p->restore();
01181 }
01182 
01183 QgsStringMap QgsFontMarkerSymbolLayerV2::properties() const
01184 {
01185   QgsStringMap props;
01186   props["font"] = mFontFamily;
01187   props["chr"] = mChr;
01188   props["size"] = QString::number( mSize );
01189   props["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
01190   props["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
01191   props["angle"] = QString::number( mAngle );
01192   props["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
01193   props["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
01194   return props;
01195 }
01196 
01197 QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::clone() const
01198 {
01199   QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( mFontFamily, mChr, mSize, mColor, mAngle );
01200   m->setOffset( mOffset );
01201   m->setOffsetUnit( mOffsetUnit );
01202   m->setSizeUnit( mSizeUnit );
01203   return m;
01204 }
01205 
01206 void QgsFontMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
01207 {
01208   // <Graphic>
01209   QDomElement graphicElem = doc.createElement( "se:Graphic" );
01210   element.appendChild( graphicElem );
01211 
01212   QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
01213   int markIndex = mChr.unicode();
01214   QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, mSize );
01215 
01216   // <Rotation>
01217   QString angleFunc;
01218   bool ok;
01219   double angle = props.value( "angle", "0" ).toDouble( &ok );
01220   if ( !ok )
01221   {
01222     angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
01223   }
01224   else if ( angle + mAngle != 0 )
01225   {
01226     angleFunc = QString::number( angle + mAngle );
01227   }
01228   QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
01229 
01230   // <Displacement>
01231   QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
01232 }
01233 
01234 QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::createFromSld( QDomElement &element )
01235 {
01236   QgsDebugMsg( "Entered." );
01237 
01238   QDomElement graphicElem = element.firstChildElement( "Graphic" );
01239   if ( graphicElem.isNull() )
01240     return NULL;
01241 
01242   QString name, format;
01243   QColor color;
01244   double size;
01245   int chr;
01246 
01247   if ( !QgsSymbolLayerV2Utils::externalMarkerFromSld( graphicElem, name, format, chr, color, size ) )
01248     return NULL;
01249 
01250   if ( !name.startsWith( "ttf://" ) || format != "ttf" )
01251     return NULL;
01252 
01253   QString fontFamily = name.mid( 6 );
01254 
01255   double angle = 0.0;
01256   QString angleFunc;
01257   if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
01258   {
01259     bool ok;
01260     double d = angleFunc.toDouble( &ok );
01261     if ( ok )
01262       angle = d;
01263   }
01264 
01265   QPointF offset;
01266   QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );
01267 
01268   QgsMarkerSymbolLayerV2 *m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, size, color );
01269   m->setAngle( angle );
01270   m->setOffset( offset );
01271   return m;
01272 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines