00001
00002 #include "qgsmarkersymbollayerv2.h"
00003 #include "qgssymbollayerv2utils.h"
00004
00005 #include "qgsrendercontext.h"
00006 #include "qgsapplication.h"
00007 #include "qgslogger.h"
00008 #include "qgsproject.h"
00009
00010 #include <QPainter>
00011 #include <QSvgRenderer>
00012 #include <QFileInfo>
00013 #include <QDir>
00014
00015 #include <cmath>
00016
00017
00018 #ifndef M_PI
00019 #define M_PI 3.14159265358979323846
00020 #endif
00021
00022 #define DEG2RAD(x) ((x)*M_PI/180)
00023
00024
00025 QgsSimpleMarkerSymbolLayerV2::QgsSimpleMarkerSymbolLayerV2( QString name, QColor color, QColor borderColor, double size, double angle )
00026 {
00027 mName = name;
00028 mColor = color;
00029 mBorderColor = borderColor;
00030 mSize = size;
00031 mAngle = angle;
00032 mOffset = QPointF( 0, 0 );
00033 }
00034
00035 QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::create( const QgsStringMap& props )
00036 {
00037 QString name = DEFAULT_SIMPLEMARKER_NAME;
00038 QColor color = DEFAULT_SIMPLEMARKER_COLOR;
00039 QColor borderColor = DEFAULT_SIMPLEMARKER_BORDERCOLOR;
00040 double size = DEFAULT_SIMPLEMARKER_SIZE;
00041 double angle = DEFAULT_SIMPLEMARKER_ANGLE;
00042
00043 if ( props.contains( "name" ) )
00044 name = props["name"];
00045 if ( props.contains( "color" ) )
00046 color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
00047 if ( props.contains( "color_border" ) )
00048 borderColor = QgsSymbolLayerV2Utils::decodeColor( props["color_border"] );
00049 if ( props.contains( "size" ) )
00050 size = props["size"].toDouble();
00051 if ( props.contains( "angle" ) )
00052 angle = props["angle"].toDouble();
00053
00054 QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size, angle );
00055 if ( props.contains( "offset" ) )
00056 m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
00057 return m;
00058 }
00059
00060
00061 QString QgsSimpleMarkerSymbolLayerV2::layerType() const
00062 {
00063 return "SimpleMarker";
00064 }
00065
00066 void QgsSimpleMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
00067 {
00068 mBrush = QBrush( mColor );
00069 mPen = QPen( mBorderColor );
00070 mPen.setWidthF( context.outputLineWidth( mPen.widthF() ) );
00071
00072 QColor selColor = context.selectionColor();
00073 mSelBrush = QBrush( selColor );
00074 mSelPen = QPen( selColor == mColor ? selColor : mBorderColor );
00075 mSelPen.setWidthF( mPen.widthF() );
00076
00077 bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation;
00078 bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale;
00079
00080
00081
00082
00083 mUsingCache = !hasDataDefinedRotation && !hasDataDefinedSize && !context.renderContext().forceVectorOutput();
00084
00085
00086
00087 if ( !prepareShape() )
00088 {
00089 if ( preparePath() )
00090 {
00091
00092
00093
00094 if ( mName != "circle" )
00095 mSelPen.setColor( selColor );
00096 }
00097 else
00098 {
00099 QgsDebugMsg( "unknown symbol" );
00100 return;
00101 }
00102 }
00103
00104 QMatrix transform;
00105
00106
00107 if ( !hasDataDefinedSize )
00108 {
00109 double scaledSize = context.outputLineWidth( mSize );
00110 if ( mUsingCache )
00111 scaledSize *= context.renderContext().rasterScaleFactor();
00112 double half = scaledSize / 2.0;
00113 transform.scale( half, half );
00114 }
00115
00116
00117 if ( !hasDataDefinedRotation && mAngle != 0 )
00118 {
00119 transform.rotate( mAngle );
00120 }
00121
00122 if ( !mPolygon.isEmpty() )
00123 mPolygon = transform.map( mPolygon );
00124 else
00125 mPath = transform.map( mPath );
00126
00127 if ( mUsingCache )
00128 {
00129 prepareCache( context );
00130 }
00131 else
00132 {
00133 mCache = QImage();
00134 mSelCache = QImage();
00135 }
00136 }
00137
00138
00139 void QgsSimpleMarkerSymbolLayerV2::prepareCache( QgsSymbolV2RenderContext& context )
00140 {
00141 double scaledSize = context.outputPixelSize( mSize );
00142
00143
00144 double pw = (( mPen.widthF() == 0 ? 1 : mPen.widthF() ) + 1 ) / 2 * 2;
00145 int imageSize = (( int ) scaledSize + pw ) / 2 * 2 + 1;
00146
00147 double center = (( double ) imageSize / 2 ) + 0.5;
00148
00149 mCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
00150 mCache.fill( 0 );
00151
00152 QPainter p;
00153 p.begin( &mCache );
00154 p.setRenderHint( QPainter::Antialiasing );
00155 p.setBrush( mBrush );
00156 p.setPen( mPen );
00157 p.translate( QPointF( center, center ) );
00158 drawMarker( &p, context );
00159 p.end();
00160
00161
00162
00163 QColor selColor = context.selectionColor();
00164
00165 mSelCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
00166 mSelCache.fill( 0 );
00167
00168 p.begin( &mSelCache );
00169 p.setRenderHint( QPainter::Antialiasing );
00170 p.setBrush( mSelBrush );
00171 p.setPen( mSelPen );
00172 p.translate( QPointF( center, center ) );
00173 drawMarker( &p, context );
00174 p.end();
00175
00176
00177
00178
00179
00180 if ( mSelCache == mCache )
00181 {
00182 p.begin( &mSelCache );
00183 p.setRenderHint( QPainter::Antialiasing );
00184 p.fillRect( 0, 0, imageSize, imageSize, selColor );
00185 p.setBrush( mBrush );
00186 p.setPen( mPen );
00187 p.translate( QPointF( center, center ) );
00188 drawMarker( &p, context );
00189 p.end();
00190 }
00191
00192
00193 if ( context.alpha() < 1.0 )
00194 {
00195 QgsSymbolLayerV2Utils::multiplyImageOpacity( &mCache, context.alpha() );
00196 if ( ! selectionIsOpaque ) QgsSymbolLayerV2Utils::multiplyImageOpacity( &mSelCache, context.alpha() );
00197 }
00198 }
00199
00200 void QgsSimpleMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
00201 {
00202 }
00203
00204 bool QgsSimpleMarkerSymbolLayerV2::prepareShape()
00205 {
00206 mPolygon.clear();
00207
00208 if ( mName == "rectangle" )
00209 {
00210 mPolygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 1, 1 ) ) );
00211 return true;
00212 }
00213 else if ( mName == "diamond" )
00214 {
00215 mPolygon << QPointF( -1, 0 ) << QPointF( 0, 1 )
00216 << QPointF( 1, 0 ) << QPointF( 0, -1 );
00217 return true;
00218 }
00219 else if ( mName == "pentagon" )
00220 {
00221 mPolygon << QPointF( sin( DEG2RAD( 288.0 ) ), - cos( DEG2RAD( 288.0 ) ) )
00222 << QPointF( sin( DEG2RAD( 216.0 ) ), - cos( DEG2RAD( 216.0 ) ) )
00223 << QPointF( sin( DEG2RAD( 144.0 ) ), - cos( DEG2RAD( 144.0 ) ) )
00224 << QPointF( sin( DEG2RAD( 72.0 ) ), - cos( DEG2RAD( 72.0 ) ) )
00225 << QPointF( 0, -1 );
00226 return true;
00227 }
00228 else if ( mName == "triangle" )
00229 {
00230 mPolygon << QPointF( -1, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 );
00231 return true;
00232 }
00233 else if ( mName == "equilateral_triangle" )
00234 {
00235 mPolygon << QPointF( sin( DEG2RAD( 240.0 ) ), - cos( DEG2RAD( 240.0 ) ) )
00236 << QPointF( sin( DEG2RAD( 120.0 ) ), - cos( DEG2RAD( 120.0 ) ) )
00237 << QPointF( 0, -1 );
00238 return true;
00239 }
00240 else if ( mName == "star" )
00241 {
00242 double sixth = 1.0 / 3;
00243
00244 mPolygon << QPointF( 0, -1 )
00245 << QPointF( -sixth, -sixth )
00246 << QPointF( -1, -sixth )
00247 << QPointF( -sixth, 0 )
00248 << QPointF( -1, 1 )
00249 << QPointF( 0, + sixth )
00250 << QPointF( 1, 1 )
00251 << QPointF( + sixth, 0 )
00252 << QPointF( 1, -sixth )
00253 << QPointF( + sixth, -sixth );
00254 return true;
00255 }
00256 else if ( mName == "regular_star" )
00257 {
00258 double inner_r = cos( DEG2RAD( 72.0 ) ) / cos( DEG2RAD( 36.0 ) );
00259
00260 mPolygon << QPointF( inner_r * sin( DEG2RAD( 324.0 ) ), - inner_r * cos( DEG2RAD( 324.0 ) ) )
00261 << QPointF( sin( DEG2RAD( 288.0 ) ) , - cos( DEG2RAD( 288 ) ) )
00262 << QPointF( inner_r * sin( DEG2RAD( 252.0 ) ), - inner_r * cos( DEG2RAD( 252.0 ) ) )
00263 << QPointF( sin( DEG2RAD( 216.0 ) ) , - cos( DEG2RAD( 216.0 ) ) )
00264 << QPointF( 0, inner_r )
00265 << QPointF( sin( DEG2RAD( 144.0 ) ) , - cos( DEG2RAD( 144.0 ) ) )
00266 << QPointF( inner_r * sin( DEG2RAD( 108.0 ) ), - inner_r * cos( DEG2RAD( 108.0 ) ) )
00267 << QPointF( sin( DEG2RAD( 72.0 ) ) , - cos( DEG2RAD( 72.0 ) ) )
00268 << QPointF( inner_r * sin( DEG2RAD( 36.0 ) ), - inner_r * cos( DEG2RAD( 36.0 ) ) )
00269 << QPointF( 0, -1 );
00270 return true;
00271 }
00272 else if ( mName == "arrow" )
00273 {
00274 mPolygon
00275 << QPointF( 0, -1 )
00276 << QPointF( 0.5, -0.5 )
00277 << QPointF( 0.25, -0.25 )
00278 << QPointF( 0.25, 1 )
00279 << QPointF( -0.25, 1 )
00280 << QPointF( -0.25, -0.5 )
00281 << QPointF( -0.5, -0.5 );
00282 return true;
00283 }
00284
00285 return false;
00286 }
00287
00288 bool QgsSimpleMarkerSymbolLayerV2::preparePath()
00289 {
00290 mPath = QPainterPath();
00291
00292 if ( mName == "circle" )
00293 {
00294 mPath.addEllipse( QRectF( -1, -1, 2, 2 ) );
00295 return true;
00296 }
00297 else if ( mName == "cross" )
00298 {
00299 mPath.moveTo( -1, 0 );
00300 mPath.lineTo( 1, 0 );
00301 mPath.moveTo( 0, -1 );
00302 mPath.lineTo( 0, 1 );
00303 return true;
00304 }
00305 else if ( mName == "cross2" )
00306 {
00307 mPath.moveTo( -1, -1 );
00308 mPath.lineTo( 1, 1 );
00309 mPath.moveTo( 1, -1 );
00310 mPath.lineTo( -1, 1 );
00311 return true;
00312 }
00313 else if ( mName == "line" )
00314 {
00315 mPath.moveTo( 0, -1 );
00316 mPath.lineTo( 0, 1 );
00317 return true;
00318 }
00319
00320 return false;
00321 }
00322
00323 void QgsSimpleMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context )
00324 {
00325 QgsRenderContext& rc = context.renderContext();
00326 QPainter* p = rc.painter();
00327 if ( !p )
00328 {
00329 return;
00330 }
00331
00332 if ( mUsingCache )
00333 {
00334
00335 QImage &img = context.selected() ? mSelCache : mCache;
00336 double s = img.width() / context.renderContext().rasterScaleFactor();
00337 p->drawImage( QRectF( point.x() - s / 2.0 + context.outputLineWidth( mOffset.x() ),
00338 point.y() - s / 2.0 + context.outputLineWidth( mOffset.y() ),
00339 s, s ), img );
00340 }
00341 else
00342 {
00343 QMatrix transform;
00344
00345
00346 bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale;
00347
00348
00349 transform.translate( point.x() + context.outputLineWidth( mOffset.x() ),
00350 point.y() + context.outputLineWidth( mOffset.y() ) );
00351
00352
00353 if ( hasDataDefinedSize )
00354 {
00355 double scaledSize = context.outputLineWidth( mSize );
00356 double half = scaledSize / 2.0;
00357 transform.scale( half, half );
00358 }
00359
00360
00361 if ( mAngle != 0 )
00362 {
00363 transform.rotate( mAngle );
00364 }
00365
00366 p->setBrush( context.selected() ? mSelBrush : mBrush );
00367 p->setPen( context.selected() ? mSelPen : mPen );
00368
00369 if ( !mPolygon.isEmpty() )
00370 p->drawPolygon( transform.map( mPolygon ) );
00371 else
00372 p->drawPath( transform.map( mPath ) );
00373 }
00374 }
00375
00376
00377 QgsStringMap QgsSimpleMarkerSymbolLayerV2::properties() const
00378 {
00379 QgsStringMap map;
00380 map["name"] = mName;
00381 map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
00382 map["color_border"] = QgsSymbolLayerV2Utils::encodeColor( mBorderColor );
00383 map["size"] = QString::number( mSize );
00384 map["angle"] = QString::number( mAngle );
00385 map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
00386 return map;
00387 }
00388
00389 QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::clone() const
00390 {
00391 QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( mName, mColor, mBorderColor, mSize, mAngle );
00392 m->setOffset( mOffset );
00393 return m;
00394 }
00395
00396 void QgsSimpleMarkerSymbolLayerV2::drawMarker( QPainter* p, QgsSymbolV2RenderContext& context )
00397 {
00398 if ( mPolygon.count() != 0 )
00399 {
00400 p->drawPolygon( mPolygon );
00401 }
00402 else
00403 {
00404 p->drawPath( mPath );
00405 }
00406 }
00407
00408
00410
00411
00412 QgsSvgMarkerSymbolLayerV2::QgsSvgMarkerSymbolLayerV2( QString name, double size, double angle )
00413 {
00414 mPath = symbolNameToPath( name );
00415 mSize = size;
00416 mAngle = angle;
00417 mOffset = QPointF( 0, 0 );
00418 }
00419
00420
00421 QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::create( const QgsStringMap& props )
00422 {
00423 QString name = DEFAULT_SVGMARKER_NAME;
00424 double size = DEFAULT_SVGMARKER_SIZE;
00425 double angle = DEFAULT_SVGMARKER_ANGLE;
00426
00427 if ( props.contains( "name" ) )
00428 name = props["name"];
00429 if ( props.contains( "size" ) )
00430 size = props["size"].toDouble();
00431 if ( props.contains( "angle" ) )
00432 angle = props["angle"].toDouble();
00433
00434 QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle );
00435 if ( props.contains( "offset" ) )
00436 m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
00437 return m;
00438 }
00439
00440
00441 QString QgsSvgMarkerSymbolLayerV2::layerType() const
00442 {
00443 return "SvgMarker";
00444 }
00445
00446 void QgsSvgMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
00447 {
00448 double pictureSize = 0;
00449 QgsRenderContext& rc = context.renderContext();
00450
00451 if ( rc.painter() && rc.painter()->device() )
00452 {
00453
00454 pictureSize = context.outputLineWidth( mSize ) / rc.painter()->device()->logicalDpiX() * mPicture.logicalDpiX();
00455 }
00456 else
00457 {
00458 pictureSize = context.outputLineWidth( mSize );
00459 }
00460 QRectF rect( QPointF( -pictureSize / 2.0, -pictureSize / 2.0 ), QSizeF( pictureSize, pictureSize ) );
00461 QSvgRenderer renderer( mPath );
00462 QPainter painter( &mPicture );
00463 renderer.render( &painter, rect );
00464 QPainter selPainter( &mSelPicture );
00465 selPainter.setRenderHint( QPainter::Antialiasing );
00466 selPainter.setBrush( QBrush( context.selectionColor() ) );
00467 selPainter.setPen( Qt::NoPen );
00468 selPainter.drawEllipse( QPointF( 0, 0 ), pictureSize*0.6, pictureSize*0.6 );
00469 renderer.render( &selPainter, rect );
00470
00471 mOrigSize = mSize;
00472 }
00473
00474 void QgsSvgMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
00475 {
00476 }
00477
00478
00479 void QgsSvgMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context )
00480 {
00481 QPainter* p = context.renderContext().painter();
00482 if ( !p )
00483 {
00484 return;
00485 }
00486
00487 p->save();
00488 QPointF outputOffset = QPointF( context.outputLineWidth( mOffset.x() ), context.outputLineWidth( mOffset.y() ) );
00489 p->translate( point + outputOffset );
00490
00491 if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
00492 {
00493 double s = mSize / mOrigSize;
00494 p->scale( s, s );
00495 }
00496
00497 if ( mAngle != 0 )
00498 p->rotate( mAngle );
00499
00500 QPicture &pct = context.selected() ? mSelPicture : mPicture;
00501 p->drawPicture( 0, 0, pct );
00502
00503 p->restore();
00504 }
00505
00506
00507 QgsStringMap QgsSvgMarkerSymbolLayerV2::properties() const
00508 {
00509 QgsStringMap map;
00510 map["name"] = symbolPathToName( mPath );
00511 map["size"] = QString::number( mSize );
00512 map["angle"] = QString::number( mAngle );
00513 map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
00514 return map;
00515 }
00516
00517 QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::clone() const
00518 {
00519 QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( mPath, mSize, mAngle );
00520 m->setOffset( mOffset );
00521 return m;
00522 }
00523
00524
00525 QStringList QgsSvgMarkerSymbolLayerV2::listSvgFiles()
00526 {
00527
00528 QStringList list;
00529 QStringList svgPaths = QgsApplication::svgPaths();
00530
00531 for ( int i = 0; i < svgPaths.size(); i++ )
00532 {
00533 QDir dir( svgPaths[i] );
00534 foreach( QString item, dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
00535 {
00536 svgPaths.insert( i + 1, dir.path() + "/" + item );
00537 }
00538
00539 foreach( QString item, dir.entryList( QStringList( "*.svg" ), QDir::Files ) )
00540 {
00541
00542 list.append( dir.path() + "/" + item );
00543 }
00544 }
00545 return list;
00546 }
00547
00548 QString QgsSvgMarkerSymbolLayerV2::symbolNameToPath( QString name )
00549 {
00550
00551
00552
00553 if ( QFile( name ).exists() )
00554 return QFileInfo( name ).canonicalFilePath();
00555
00556
00557
00558 QStringList svgPaths = QgsApplication::svgPaths();
00559 for ( int i = 0; i < svgPaths.size(); i++ )
00560 {
00561 QgsDebugMsg( "SvgPath: " + svgPaths[i] );
00562 QFileInfo myInfo( name );
00563 QString myFileName = myInfo.fileName();
00564 QString myLowestDir = myInfo.dir().dirName();
00565 QString myLocalPath = svgPaths[i] + "/" + myLowestDir + "/" + myFileName;
00566
00567 QgsDebugMsg( "Alternative svg path: " + myLocalPath );
00568 if ( QFile( myLocalPath ).exists() )
00569 {
00570 QgsDebugMsg( "Svg found in alternative path" );
00571 return QFileInfo( myLocalPath ).canonicalFilePath();
00572 }
00573 else if ( myInfo.isRelative() )
00574 {
00575 QFileInfo pfi( QgsProject::instance()->fileName() );
00576 QString alternatePath = pfi.canonicalPath() + QDir::separator() + name;
00577 if ( pfi.exists() && QFile( alternatePath ).exists() )
00578 {
00579 QgsDebugMsg( "Svg found in alternative path" );
00580 return QFileInfo( alternatePath ).canonicalFilePath();
00581 }
00582 else
00583 {
00584 QgsDebugMsg( "Svg not found in project path" );
00585 }
00586 }
00587 else
00588 {
00589
00590 QgsDebugMsg( "Computed alternate path but no svg there either" );
00591 }
00592 }
00593 return QString();
00594 }
00595
00596 QString QgsSvgMarkerSymbolLayerV2::symbolPathToName( QString path )
00597 {
00598
00599
00600 QFileInfo fi( path );
00601 if ( !fi.exists() )
00602 return path;
00603
00604 path = fi.canonicalFilePath();
00605
00606 QStringList svgPaths = QgsApplication::svgPaths();
00607
00608 for ( int i = 0; i < svgPaths.size(); i++ )
00609 {
00610 QString dir = QFileInfo( svgPaths[i] ).canonicalFilePath();
00611
00612 if ( !dir.isEmpty() && path.startsWith( dir ) )
00613 {
00614 path = path.mid( dir.size() );
00615 break;
00616 }
00617 }
00618
00619 return path;
00620 }
00621
00622
00624
00625 QgsFontMarkerSymbolLayerV2::QgsFontMarkerSymbolLayerV2( QString fontFamily, QChar chr, double pointSize, QColor color, double angle )
00626 {
00627 mFontFamily = fontFamily;
00628 mChr = chr;
00629 mColor = color;
00630 mAngle = angle;
00631 mSize = pointSize;
00632 }
00633
00634 QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::create( const QgsStringMap& props )
00635 {
00636 QString fontFamily = DEFAULT_FONTMARKER_FONT;
00637 QChar chr = DEFAULT_FONTMARKER_CHR;
00638 double pointSize = DEFAULT_FONTMARKER_SIZE;
00639 QColor color = DEFAULT_FONTMARKER_COLOR;
00640 double angle = DEFAULT_FONTMARKER_ANGLE;
00641
00642 if ( props.contains( "font" ) )
00643 fontFamily = props["font"];
00644 if ( props.contains( "chr" ) && props["chr"].length() > 0 )
00645 chr = props["chr"].at( 0 );
00646 if ( props.contains( "size" ) )
00647 pointSize = props["size"].toDouble();
00648 if ( props.contains( "color" ) )
00649 color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
00650 if ( props.contains( "angle" ) )
00651 angle = props["angle"].toDouble();
00652
00653 return new QgsFontMarkerSymbolLayerV2( fontFamily, chr, pointSize, color, angle );
00654 }
00655
00656 QString QgsFontMarkerSymbolLayerV2::layerType() const
00657 {
00658 return "FontMarker";
00659 }
00660
00661 void QgsFontMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
00662 {
00663 mFont = QFont( mFontFamily );
00664 mFont.setPixelSize( context.outputLineWidth( mSize ) );
00665 QFontMetrics fm( mFont );
00666 mChrOffset = QPointF( fm.width( mChr ) / 2, -fm.ascent() / 2 );
00667
00668 mOrigSize = mSize;
00669 }
00670
00671 void QgsFontMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
00672 {
00673 }
00674
00675 void QgsFontMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context )
00676 {
00677 QPainter* p = context.renderContext().painter();
00678 QColor penColor = context.selected() ? context.selectionColor() : mColor;
00679 penColor.setAlphaF( context.alpha() );
00680 p->setPen( penColor );
00681 p->setFont( mFont );
00682
00683 p->save();
00684 p->translate( point );
00685
00686 if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
00687 {
00688 double s = mSize / mOrigSize;
00689 p->scale( s, s );
00690 }
00691
00692 if ( mAngle != 0 )
00693 p->rotate( mAngle );
00694
00695 p->drawText( -mChrOffset, mChr );
00696 p->restore();
00697 }
00698
00699 QgsStringMap QgsFontMarkerSymbolLayerV2::properties() const
00700 {
00701 QgsStringMap props;
00702 props["font"] = mFontFamily;
00703 props["chr"] = mChr;
00704 props["size"] = QString::number( mSize );
00705 props["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
00706 props["angle"] = QString::number( mAngle );
00707 return props;
00708 }
00709
00710 QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::clone() const
00711 {
00712 return new QgsFontMarkerSymbolLayerV2( mFontFamily, mChr, mSize, mColor, mAngle );
00713 }